diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5c23fd3b65..5273ac994b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -42,6 +42,9 @@ jobs: - run: ./target/release/ruff_dev generate-check-code-prefix - run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. You may have to rerun 'cargo dev generate-check-code-prefix'." - run: git diff --exit-code -- README.md src/checks_gen.rs + - run: ./target/release/ruff_dev generate-json-schema + - run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. You may have to rerun 'cargo dev generate-json-schema'." + - run: git diff --exit-code -- ruff.schema.json cargo_fmt: name: "cargo fmt" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff359c3a10..aadef7bcfb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,7 +105,8 @@ You may also want to add the new configuration option to the `flake8-to-ruff` to responsible for converting `flake8` configuration files to Ruff's TOML format. This logic lives in `flake8_to_ruff/src/converter.rs`. -To update the documentation for supported configuration options, run `cargo dev generate-options`. +Run `cargo dev generate-options` to update the documentation for supported configuration options, +and `cargo dev generate-json-schema` to update the JSON schema for `tool.ruff` in `pyproject.toml`. ## Release process diff --git a/Cargo.lock b/Cargo.lock index c22652658e..a43f0359b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -644,6 +644,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dyn-clone" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" + [[package]] name = "either" version = "1.8.0" @@ -1888,6 +1894,7 @@ dependencies = [ "rustpython-ast", "rustpython-common", "rustpython-parser", + "schemars", "serde", "serde_json", "shellexpand", @@ -1916,6 +1923,8 @@ dependencies = [ "rustpython-ast", "rustpython-common", "rustpython-parser", + "schemars", + "serde_json", "strum", "strum_macros", ] @@ -2058,6 +2067,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -2107,10 +2140,21 @@ dependencies = [ ] [[package]] -name = "serde_json" -version = "1.0.89" +name = "serde_derive_internals" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index e4cf0e2c1b..2643985081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ rustc-hash = { version = "1.1.0" } rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" } rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" } rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" } +schemars = { version = "0.8.11" } serde = { version = "1.0.147", features = ["derive"] } serde_json = { version = "1.0.87" } shellexpand = { version = "3.0.0" } diff --git a/README.md b/README.md index 79cf612584..376324cfde 100644 --- a/README.md +++ b/README.md @@ -1581,8 +1581,8 @@ Summary #### [`allowed-confusables`](#allowed-confusables) -A list of allowed "confusable" Unicode characters to ignore when enforcing `RUF001`, -`RUF002`, and `RUF003`. +A list of allowed "confusable" Unicode characters to ignore when +enforcing `RUF001`, `RUF002`, and `RUF003`. **Default value**: `[]` @@ -1603,13 +1603,14 @@ allowed-confusables = ["−", "ρ", "∗"] A path to the cache directory. -By default, Ruff stores cache results in a `.ruff_cache` directory in the current -project root. +By default, Ruff stores cache results in a `.ruff_cache` directory in +the current project root. -However, Ruff will also respect the `RUFF_CACHE_DIR` environment variable, which takes -precedence over that default. +However, Ruff will also respect the `RUFF_CACHE_DIR` environment +variable, which takes precedence over that default. -This setting will override even the `RUFF_CACHE_DIR` environment variable, if set. +This setting will override even the `RUFF_CACHE_DIR` environment +variable, if set. **Default value**: `.ruff_cache` @@ -1626,9 +1627,9 @@ cache-dir = "~/.cache/ruff" #### [`dummy-variable-rgx`](#dummy-variable-rgx) -A regular expression used to identify "dummy" variables, or those which should be -ignored when evaluating (e.g.) unused-variable checks. The default expression matches -`_`, `__`, and `_var`, but not `_var_`. +A regular expression used to identify "dummy" variables, or those which +should be ignored when evaluating (e.g.) unused-variable checks. The +default expression matches `_`, `__`, and `_var`, but not `_var_`. **Default value**: `"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"` @@ -1650,15 +1651,16 @@ 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 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`). +- 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`). -Note that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify -the excluded paths. +Note that you'll typically want to use +[`extend-exclude`](#extend-exclude) to modify the excluded paths. **Default value**: `[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]` @@ -1675,12 +1677,13 @@ exclude = [".venv"] #### [`extend`](#extend) -A path to a local `pyproject.toml` file to merge into this configuration. User home -directory and environment variables will be expanded. +A path to a local `pyproject.toml` file to merge into this +configuration. User home directory and environment variables will be +expanded. -To resolve the current `pyproject.toml` file, Ruff will first resolve this base -configuration file, then merge in any properties defined in the current configuration -file. +To resolve the current `pyproject.toml` file, Ruff will first resolve +this base configuration file, then merge in any properties defined +in the current configuration file. **Default value**: `None` @@ -1700,7 +1703,8 @@ line-length = 100 #### [`extend-exclude`](#extend-exclude) -A list of file patterns to omit from linting, in addition to those specified by `exclude`. +A list of file patterns to omit from linting, in addition to those +specified by `exclude`. **Default value**: `[]` @@ -1718,7 +1722,8 @@ extend-exclude = ["tests", "src/bad.py"] #### [`extend-ignore`](#extend-ignore) -A list of check code prefixes to ignore, in addition to those specified by `ignore`. +A list of check code prefixes to ignore, in addition to those specified +by `ignore`. **Default value**: `[]` @@ -1736,7 +1741,8 @@ extend-ignore = ["F841"] #### [`extend-select`](#extend-select) -A list of check code prefixes to enable, in addition to those specified by `select`. +A list of check code prefixes to enable, in addition to those specified +by `select`. **Default value**: `[]` @@ -1754,9 +1760,10 @@ extend-select = ["B", "Q"] #### [`external`](#external) -A list of check codes that are unsupported by Ruff, but should be preserved when (e.g.) -validating `# noqa` directives. Useful for retaining `# noqa` directives that cover plugins not -yet implemented in Ruff. +A list of check codes that are unsupported by Ruff, but should be +preserved when (e.g.) validating `# noqa` directives. Useful for +retaining `# noqa` directives that cover plugins not yet implemented +in Ruff. **Default value**: `[]` @@ -1811,14 +1818,16 @@ fixable = ["E", "F"] #### [`force-exclude`](#force-exclude) -Whether to enforce `exclude` and `extend-exclude` patterns, even for paths that are -passed to Ruff explicitly. Typically, Ruff will lint any paths passed in directly, even -if they would typically be excluded. Setting `force-exclude = true` will cause Ruff to +Whether to enforce `exclude` and `extend-exclude` patterns, even for +paths that are passed to Ruff explicitly. Typically, Ruff will lint +any paths passed in directly, even if they would typically be +excluded. Setting `force-exclude = true` will cause Ruff to respect these exclusions unequivocally. This is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all changed files to the [`ruff-pre-commit`](https://github.com/charliermarsh/ruff-pre-commit) -plugin, regardless of whether they're marked as excluded by Ruff's own settings. +plugin, regardless of whether they're marked as excluded by Ruff's own +settings. **Default value**: `false` @@ -1835,9 +1844,10 @@ force-exclude = true #### [`format`](#format) -The style in which violation messages should be formatted: `"text"` (default), -`"grouped"` (group messages by file), `"json"` (machine-readable), `"junit"` -(machine-readable XML), or `"github"` (GitHub Actions annotations). +The style in which violation messages should be formatted: `"text"` +(default), `"grouped"` (group messages by file), `"json"` +(machine-readable), `"junit"` (machine-readable XML), or `"github"` +(GitHub Actions annotations). **Default value**: `"text"` @@ -1855,11 +1865,13 @@ format = "grouped" #### [`ignore`](#ignore) -A list of check code prefixes to ignore. Prefixes can specify exact checks (like -`F841`), entire categories (like `F`), or anything in between. +A list of check code prefixes to ignore. Prefixes can specify exact +checks (like `F841`), entire categories (like `F`), or anything in +between. -When breaking ties between enabled and disabled checks (via `select` and `ignore`, -respectively), more specific prefixes override less specific prefixes. +When breaking ties between enabled and disabled checks (via `select` and +`ignore`, respectively), more specific prefixes override less +specific prefixes. **Default value**: `[]` @@ -1877,10 +1889,11 @@ ignore = ["F841"] #### [`ignore-init-module-imports`](#ignore-init-module-imports) -Avoid automatically removing unused imports in `__init__.py` files. Such imports will -still be +flagged, but with a dedicated message suggesting that the import is either -added to the module' +`__all__` symbol, or re-exported with a redundant alias (e.g., -`import os as os`). +Avoid automatically removing unused imports in `__init__.py` files. Such +imports will still be +flagged, but with a dedicated message +suggesting that the import is either added to the module' +`__all__` +symbol, or re-exported with a redundant alias (e.g., `import os as +os`). **Default value**: `false` @@ -1897,7 +1910,8 @@ ignore-init-module-imports = true #### [`line-length`](#line-length) -The line length to use when enforcing long-lines violations (like E501). +The line length to use when enforcing long-lines violations (like +`E501`). **Default value**: `88` @@ -1915,8 +1929,8 @@ line-length = 120 #### [`per-file-ignores`](#per-file-ignores) -A list of mappings from file pattern to check code prefixes to exclude, when considering -any matching files. +A list of mappings from file pattern to check code prefixes to exclude, +when considering any matching files. **Default value**: `{}` @@ -1936,8 +1950,9 @@ any matching files. #### [`respect-gitignore`](#respect-gitignore) -Whether to automatically exclude files that are ignored by `.ignore`, `.gitignore`, -`.git/info/exclude`, and global `gitignore` files. Enabled by default. +Whether to automatically exclude files that are ignored by `.ignore`, +`.gitignore`, `.git/info/exclude`, and global `gitignore` files. +Enabled by default. **Default value**: `true` @@ -1954,11 +1969,13 @@ respect_gitignore = false #### [`select`](#select) -A list of check code prefixes to enable. Prefixes can specify exact checks (like -`F841`), entire categories (like `F`), or anything in between. +A list of check code prefixes to enable. Prefixes can specify exact +checks (like `F841`), entire categories (like `F`), or anything in +between. -When breaking ties between enabled and disabled checks (via `select` and `ignore`, -respectively), more specific prefixes override less specific prefixes. +When breaking ties between enabled and disabled checks (via `select` and +`ignore`, respectively), more specific prefixes override less +specific prefixes. **Default value**: `["E", "F"]` @@ -1976,8 +1993,8 @@ select = ["E", "F", "B", "Q"] #### [`show-source`](#show-source) -Whether to show source code snippets when reporting lint error violations (overridden by -the `--show-source` command-line flag). +Whether to show source code snippets when reporting lint error +violations (overridden by the `--show-source` command-line flag). **Default value**: `false` @@ -1995,7 +2012,8 @@ show-source = true #### [`src`](#src) -The source code paths to consider, e.g., when resolving first- vs. third-party imports. +The source code paths to consider, e.g., when resolving first- vs. +third-party imports. As an example: given a Python package structure like: @@ -2009,13 +2027,15 @@ my_package/ bar.py ``` -The `src` directory should be included in `source` (e.g., `source = ["src"]`), such that -when resolving imports, `my_package.foo` is considered a first-party import. +The `src` directory should be included in `source` (e.g., `source = +["src"]`), such that when resolving imports, `my_package.foo` is +considered a first-party import. -This field supports globs. For example, if you have a series of Python packages in -a `python_modules` directory, `src = ["python_modules/*"]` would expand to incorporate -all of the packages in that directory. User home directory and environment variables -will also be expanded. +This field supports globs. For example, if you have a series of Python +packages in a `python_modules` directory, `src = +["python_modules/*"]` would expand to incorporate all of the +packages in that directory. User home directory and environment +variables will also be expanded. **Default value**: `["."]` @@ -2033,9 +2053,10 @@ src = ["src", "test"] #### [`target-version`](#target-version) -The Python version to target, e.g., when considering automatic code upgrades, like -rewriting type annotations. Note that the target version will _not_ be inferred from the -_current_ Python version, and instead must be specified explicitly (as seen below). +The Python version to target, e.g., when considering automatic code +upgrades, like rewriting type annotations. Note that the target +version will _not_ be inferred from the _current_ Python version, +and instead must be specified explicitly (as seen below). **Default value**: `"py310"` @@ -2073,7 +2094,8 @@ unfixable = ["F401"] #### [`allow-star-arg-any`](#allow-star-arg-any) -Whether to suppress `ANN401` for dynamically typed `*args` and `**kwargs` arguments. +Whether to suppress `ANN401` for dynamically typed `*args` and +`**kwargs` arguments. **Default value**: `false` @@ -2090,8 +2112,8 @@ allow-star-arg-any = true #### [`mypy-init-return`](#mypy-init-return) -Whether to allow the omission of a return type hint for `__init__` if at least one -argument is annotated. +Whether to allow the omission of a return type hint for `__init__` if at +least one argument is annotated. **Default value**: `false` @@ -2108,8 +2130,8 @@ mypy-init-return = true #### [`suppress-dummy-args`](#suppress-dummy-args) -Whether to suppress `ANN000`-level errors for arguments matching the "dummy" variable -regex (like `_`). +Whether to suppress `ANN000`-level errors for arguments matching the +"dummy" variable regex (like `_`). **Default value**: `false` @@ -2126,11 +2148,12 @@ suppress-dummy-args = true #### [`suppress-none-returning`](#suppress-none-returning) -Whether to suppress `ANN200`-level errors for functions that meet either of the -following criteria: +Whether to suppress `ANN200`-level errors for functions that meet either +of the following criteria: - Contain no `return` statement. -- Explicit `return` statement(s) all return `None` (explicitly or implicitly). +- Explicit `return` statement(s) all return `None` (explicitly or + implicitly). **Default value**: `false` @@ -2149,8 +2172,8 @@ suppress-none-returning = true #### [`extend-immutable-calls`](#extend-immutable-calls) -Additional callable functions to consider "immutable" when evaluating, e.g., -`no-mutable-default-argument` checks (`B006`). +Additional callable functions to consider "immutable" when evaluating, +e.g., `no-mutable-default-argument` checks (`B006`). **Default value**: `[]` @@ -2189,7 +2212,8 @@ max-string-length = 20 #### [`aliases`](#aliases) -The conventional aliases for imports. These aliases can be extended by the `extend_aliases` option. +The conventional aliases for imports. These aliases can be extended by +the `extend_aliases` option. **Default value**: `{"altair": "alt", "matplotlib.pyplot": "plt", "numpy": "np", "pandas": "pd", "seaborn": "sns"}` @@ -2211,7 +2235,8 @@ seaborn = "sns" #### [`extend-aliases`](#extend-aliases) -A mapping of modules to their conventional import aliases. These aliases will be added to the `aliases` mapping. +A mapping of modules to their conventional import aliases. These aliases +will be added to the `aliases` mapping. **Default value**: `{}` @@ -2231,8 +2256,8 @@ A mapping of modules to their conventional import aliases. These aliases will be #### [`avoid-escape`](#avoid-escape) -Whether to avoid using single quotes if a string contains single quotes, or vice-versa -with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes). +Whether to avoid using single quotes if a string contains single quotes, +or vice-versa with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes). This minimizes the need to escape quotation marks within strings. **Default value**: `true` @@ -2251,7 +2276,8 @@ avoid-escape = false #### [`docstring-quotes`](#docstring-quotes) -Quote style to prefer for docstrings (either "single" (`'`) or "double" (`"`)). +Quote style to prefer for docstrings (either "single" (`'`) or "double" +(`"`)). **Default value**: `"double"` @@ -2268,7 +2294,8 @@ docstring-quotes = "single" #### [`inline-quotes`](#inline-quotes) -Quote style to prefer for inline strings (either "single" (`'`) or "double" (`"`)). +Quote style to prefer for inline strings (either "single" (`'`) or +"double" (`"`)). **Default value**: `"double"` @@ -2285,7 +2312,8 @@ inline-quotes = "single" #### [`multiline-quotes`](#multiline-quotes) -Quote style to prefer for multiline strings (either "single" (`'`) or "double" (`"`)). +Quote style to prefer for multiline strings (either "single" (`'`) or +"double" (`"`)). **Default value**: `"double"` @@ -2304,8 +2332,8 @@ multiline-quotes = "single" #### [`ban-relative-imports`](#ban-relative-imports) -Whether to ban all relative imports (`"all"`), or only those imports that extend into -the parent module and beyond (`"parents"`). +Whether to ban all relative imports (`"all"`), or only those imports +that extend into the parent module and beyond (`"parents"`). **Default value**: `"parents"` @@ -2362,8 +2390,8 @@ combine-as-imports = true #### [`extra-standard-library`](#extra-standard-library) -A list of modules to consider standard-library, in addition to those known to Ruff in -advance. +A list of modules to consider standard-library, in addition to those +known to Ruff in advance. **Default value**: `[]` @@ -2380,9 +2408,10 @@ extra-standard-library = ["path"] #### [`force-wrap-aliases`](#force-wrap-aliases) -Force `import from` statements with multiple members and at least one alias (e.g., -`import A as B`) to wrap such that every line contains exactly one member. For example, -this formatting would be retained, rather than condensing to a single line: +Force `import from` statements with multiple members and at least one +alias (e.g., `import A as B`) to wrap such that every line contains +exactly one member. For example, this formatting would be retained, +rather than condensing to a single line: ```py from .utils import ( @@ -2391,9 +2420,10 @@ from .utils import ( ) ``` -Note that this setting is only effective when combined with `combine-as-imports = true`. -When `combine-as-imports` isn't enabled, every aliased `import from` will be given its -own line, in which case, wrapping is not necessary. +Note that this setting is only effective when combined with +`combine-as-imports = true`. When `combine-as-imports` isn't +enabled, every aliased `import from` will be given its own line, in +which case, wrapping is not necessary. **Default value**: `false` @@ -2411,8 +2441,8 @@ combine-as-imports = true #### [`known-first-party`](#known-first-party) -A list of modules to consider first-party, regardless of whether they can be identified -as such via introspection of the local filesystem. +A list of modules to consider first-party, regardless of whether they +can be identified as such via introspection of the local filesystem. **Default value**: `[]` @@ -2429,8 +2459,8 @@ known-first-party = ["src"] #### [`known-third-party`](#known-third-party) -A list of modules to consider third-party, regardless of whether they can be identified -as such via introspection of the local filesystem. +A list of modules to consider third-party, regardless of whether they +can be identified as such via introspection of the local filesystem. **Default value**: `[]` @@ -2469,9 +2499,10 @@ max-complexity = 5 #### [`classmethod-decorators`](#classmethod-decorators) -A list of decorators that, when applied to a method, indicate that the method should be -treated as a class method. For example, Ruff will expect that any method decorated by a -decorator in this list takes a `cls` argument as its first argument. +A list of decorators that, when applied to a method, indicate that the +method should be treated as a class method. For example, Ruff will +expect that any method decorated by a decorator in this list takes a +`cls` argument as its first argument. **Default value**: `["classmethod"]` @@ -2506,9 +2537,10 @@ ignore-names = ["callMethod"] #### [`staticmethod-decorators`](#staticmethod-decorators) -A list of decorators that, when applied to a method, indicate that the method should be -treated as a static method. For example, Ruff will expect that any method decorated by a -decorator in this list has no `self` or `cls` argument. +A list of decorators that, when applied to a method, indicate that the +method should be treated as a static method. For example, Ruff will +expect that any method decorated by a decorator in this list has no +`self` or `cls` argument. **Default value**: `["staticmethod"]` @@ -2528,7 +2560,11 @@ staticmethod-decorators = ["staticmethod", "stcmthd"] #### [`keep-runtime-typing`](#keep-runtime-typing) -Whether to avoid PEP 585 (`List[int]` -> `list[int]`) and PEP 604 (`Optional[str]` -> `str | None`) rewrites even if a file imports `from __future__ import annotations`. Note that this setting is only applicable when the target Python version is below 3.9 and 3.10 respectively. +Whether to avoid PEP 585 (`List[int]` -> `list[int]`) and PEP 604 +(`Optional[str]` -> `str | None`) rewrites even if a file imports `from +__future__ import annotations`. Note that this setting is only +applicable when the target Python version is below 3.9 and 3.10 +respectively. **Default value**: `false` diff --git a/flake8_to_ruff/src/converter.rs b/flake8_to_ruff/src/converter.rs index a33165ff2f..b03409f307 100644 --- a/flake8_to_ruff/src/converter.rs +++ b/flake8_to_ruff/src/converter.rs @@ -67,10 +67,7 @@ pub fn convert( } let from_codes = plugin::infer_plugins_from_codes(&referenced_codes); if !from_codes.is_empty() { - eprintln!( - "Inferred plugins from referenced check codes: {:#?}", - from_codes - ); + eprintln!("Inferred plugins from referenced check codes: {from_codes:#?}"); } from_options.into_iter().chain(from_codes).collect() }), diff --git a/ruff.schema.json b/ruff.schema.json new file mode 100644 index 0000000000..3c43892cf1 --- /dev/null +++ b/ruff.schema.json @@ -0,0 +1,1194 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Options", + "type": "object", + "properties": { + "allowed-confusables": { + "description": "A list of allowed \"confusable\" Unicode characters to ignore when enforcing `RUF001`, `RUF002`, and `RUF003`.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "maxLength": 1, + "minLength": 1 + } + }, + "cache-dir": { + "description": "A path to the cache directory.\n\nBy default, Ruff stores cache results in a `.ruff_cache` directory in the current project root.\n\nHowever, Ruff will also respect the `RUFF_CACHE_DIR` environment variable, which takes precedence over that default.\n\nThis setting will override even the `RUFF_CACHE_DIR` environment variable, if set.", + "type": [ + "string", + "null" + ] + }, + "dummy-variable-rgx": { + "description": "A regular expression used to identify \"dummy\" variables, or those which should be ignored when evaluating (e.g.) unused-variable checks. The default expression matches `_`, `__`, and `_var`, but not `_var_`.", + "type": [ + "string", + "null" + ] + }, + "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\nNote that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify the excluded paths.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "extend": { + "description": "A path to a local `pyproject.toml` file to merge into this configuration. User home directory and environment variables will be expanded.\n\nTo resolve the current `pyproject.toml` file, Ruff will first resolve this base configuration file, then merge in any properties defined in the current configuration file.", + "type": [ + "string", + "null" + ] + }, + "extend-exclude": { + "description": "A list of file patterns to omit from linting, in addition to those specified by `exclude`.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "extend-ignore": { + "description": "A list of check code prefixes to ignore, in addition to those specified by `ignore`.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + }, + "extend-select": { + "description": "A list of check code prefixes to enable, in addition to those specified by `select`.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + }, + "external": { + "description": "A list of check codes that are unsupported by Ruff, but should be preserved when (e.g.) validating `# noqa` directives. Useful for retaining `# noqa` directives that cover plugins not yet implemented in Ruff.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "fix": { + "description": "Enable autofix behavior by-default when running `ruff` (overridden by the `--fix` and `--no-fix` command-line flags).", + "type": [ + "boolean", + "null" + ] + }, + "fixable": { + "description": "A list of check code prefixes to consider autofix-able.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + }, + "flake8-annotations": { + "description": "Plugins Options for the `flake8-annotations` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8AnnotationsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-bugbear": { + "description": "Options for the `flake8-bugbear` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8BugbearOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-errmsg": { + "description": "Options for the `flake8-errmsg` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8ErrMsgOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-import-conventions": { + "description": "Options for the `flake8-import-conventions` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8ImportConventionsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-quotes": { + "description": "Options for the `flake8-quotes` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8QuotesOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-tidy-imports": { + "description": "Options for the `flake8-tidy-imports` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8TidyImportsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-unused-arguments": { + "description": "Options for the `flake8-unused-arguments` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8UnusedArgumentsOptions" + }, + { + "type": "null" + } + ] + }, + "force-exclude": { + "description": "Whether to enforce `exclude` and `extend-exclude` patterns, even for paths that are passed to Ruff explicitly. Typically, Ruff will lint any paths passed in directly, even if they would typically be excluded. Setting `force-exclude = true` will cause Ruff to respect these exclusions unequivocally.\n\nThis is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all changed files to the [`ruff-pre-commit`](https://github.com/charliermarsh/ruff-pre-commit) plugin, regardless of whether they're marked as excluded by Ruff's own settings.", + "type": [ + "boolean", + "null" + ] + }, + "format": { + "description": "The style in which violation messages should be formatted: `\"text\"` (default), `\"grouped\"` (group messages by file), `\"json\"` (machine-readable), `\"junit\"` (machine-readable XML), or `\"github\"` (GitHub Actions annotations).", + "anyOf": [ + { + "$ref": "#/definitions/SerializationFormat" + }, + { + "type": "null" + } + ] + }, + "ignore": { + "description": "A list of check code prefixes to ignore. Prefixes can specify exact checks (like `F841`), entire categories (like `F`), or anything in between.\n\nWhen breaking ties between enabled and disabled checks (via `select` and `ignore`, respectively), more specific prefixes override less specific prefixes.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + }, + "ignore-init-module-imports": { + "description": "Avoid automatically removing unused imports in `__init__.py` files. Such imports will still be +flagged, but with a dedicated message suggesting that the import is either added to the module' +`__all__` symbol, or re-exported with a redundant alias (e.g., `import os as os`).", + "type": [ + "boolean", + "null" + ] + }, + "isort": { + "description": "Options for the `isort` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/IsortOptions" + }, + { + "type": "null" + } + ] + }, + "line-length": { + "description": "The line length to use when enforcing long-lines violations (like `E501`).", + "type": [ + "integer", + "null" + ], + "format": "uint", + "minimum": 0.0 + }, + "mccabe": { + "description": "Options for the `mccabe` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/McCabeOptions" + }, + { + "type": "null" + } + ] + }, + "pep8-naming": { + "description": "Options for the `pep8-naming` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Pep8NamingOptions" + }, + { + "type": "null" + } + ] + }, + "per-file-ignores": { + "description": "A list of mappings from file pattern to check code prefixes to exclude, when considering any matching files.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + } + }, + "pyupgrade": { + "description": "Options for the `pyupgrade` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/PyUpgradeOptions" + }, + { + "type": "null" + } + ] + }, + "respect-gitignore": { + "description": "Whether to automatically exclude files that are ignored by `.ignore`, `.gitignore`, `.git/info/exclude`, and global `gitignore` files. Enabled by default.", + "type": [ + "boolean", + "null" + ] + }, + "select": { + "description": "A list of check code prefixes to enable. Prefixes can specify exact checks (like `F841`), entire categories (like `F`), or anything in between.\n\nWhen breaking ties between enabled and disabled checks (via `select` and `ignore`, respectively), more specific prefixes override less specific prefixes.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + }, + "show-source": { + "description": "Whether to show source code snippets when reporting lint error violations (overridden by the `--show-source` command-line flag).", + "type": [ + "boolean", + "null" + ] + }, + "src": { + "description": "The source code paths to consider, e.g., when resolving first- vs. third-party imports.\n\nAs an example: given a Python package structure like:\n\n```text my_package/ pyproject.toml src/ my_package/ __init__.py foo.py bar.py ```\n\nThe `src` directory should be included in `source` (e.g., `source = [\"src\"]`), such that when resolving imports, `my_package.foo` is considered a first-party import.\n\nThis field supports globs. For example, if you have a series of Python packages in a `python_modules` directory, `src = [\"python_modules/*\"]` would expand to incorporate all of the packages in that directory. User home directory and environment variables will also be expanded.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "target-version": { + "description": "The Python version to target, e.g., when considering automatic code upgrades, like rewriting type annotations. Note that the target version will _not_ be inferred from the _current_ Python version, and instead must be specified explicitly (as seen below).", + "anyOf": [ + { + "$ref": "#/definitions/PythonVersion" + }, + { + "type": "null" + } + ] + }, + "unfixable": { + "description": "A list of check code prefixes to consider un-autofix-able.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CheckCodePrefix" + } + } + }, + "additionalProperties": false, + "definitions": { + "CheckCodePrefix": { + "type": "string", + "enum": [ + "A", + "A0", + "A00", + "A001", + "A002", + "A003", + "ANN", + "ANN0", + "ANN00", + "ANN001", + "ANN002", + "ANN003", + "ANN1", + "ANN10", + "ANN101", + "ANN102", + "ANN2", + "ANN20", + "ANN201", + "ANN202", + "ANN204", + "ANN205", + "ANN206", + "ANN4", + "ANN40", + "ANN401", + "ARG", + "ARG0", + "ARG00", + "ARG001", + "ARG002", + "ARG003", + "ARG004", + "ARG005", + "B", + "B0", + "B00", + "B002", + "B003", + "B004", + "B005", + "B006", + "B007", + "B008", + "B009", + "B01", + "B010", + "B011", + "B012", + "B013", + "B014", + "B015", + "B016", + "B017", + "B018", + "B019", + "B02", + "B020", + "B021", + "B022", + "B023", + "B024", + "B025", + "B026", + "B027", + "B9", + "B90", + "B904", + "B905", + "BLE", + "BLE0", + "BLE00", + "BLE001", + "C", + "C4", + "C40", + "C400", + "C401", + "C402", + "C403", + "C404", + "C405", + "C406", + "C408", + "C409", + "C41", + "C410", + "C411", + "C413", + "C414", + "C415", + "C416", + "C417", + "C9", + "C90", + "C901", + "D", + "D1", + "D10", + "D100", + "D101", + "D102", + "D103", + "D104", + "D105", + "D106", + "D107", + "D2", + "D20", + "D200", + "D201", + "D202", + "D203", + "D204", + "D205", + "D206", + "D207", + "D208", + "D209", + "D21", + "D210", + "D211", + "D212", + "D213", + "D214", + "D215", + "D3", + "D30", + "D300", + "D301", + "D4", + "D40", + "D400", + "D402", + "D403", + "D404", + "D405", + "D406", + "D407", + "D408", + "D409", + "D41", + "D410", + "D411", + "D412", + "D413", + "D414", + "D415", + "D416", + "D417", + "D418", + "D419", + "DTZ", + "DTZ0", + "DTZ00", + "DTZ001", + "DTZ002", + "DTZ003", + "DTZ004", + "DTZ005", + "DTZ006", + "DTZ007", + "DTZ01", + "DTZ011", + "DTZ012", + "E", + "E4", + "E40", + "E401", + "E402", + "E5", + "E50", + "E501", + "E7", + "E71", + "E711", + "E712", + "E713", + "E714", + "E72", + "E721", + "E722", + "E73", + "E731", + "E74", + "E741", + "E742", + "E743", + "E9", + "E90", + "E902", + "E99", + "E999", + "EM", + "EM1", + "EM10", + "EM101", + "EM102", + "EM103", + "ERA", + "ERA0", + "ERA00", + "ERA001", + "F", + "F4", + "F40", + "F401", + "F402", + "F403", + "F404", + "F405", + "F406", + "F407", + "F5", + "F50", + "F501", + "F502", + "F503", + "F504", + "F505", + "F506", + "F507", + "F508", + "F509", + "F52", + "F521", + "F522", + "F523", + "F524", + "F525", + "F54", + "F541", + "F6", + "F60", + "F601", + "F602", + "F62", + "F621", + "F622", + "F63", + "F631", + "F632", + "F633", + "F634", + "F7", + "F70", + "F701", + "F702", + "F704", + "F706", + "F707", + "F72", + "F722", + "F8", + "F81", + "F811", + "F82", + "F821", + "F822", + "F823", + "F83", + "F831", + "F84", + "F841", + "F842", + "F9", + "F90", + "F901", + "FBT", + "FBT0", + "FBT00", + "FBT001", + "FBT002", + "FBT003", + "I", + "I0", + "I00", + "I001", + "I2", + "I25", + "I252", + "IC", + "IC0", + "IC001", + "IC002", + "IC003", + "IC004", + "ICN", + "ICN0", + "ICN00", + "ICN001", + "M", + "M0", + "M001", + "N", + "N8", + "N80", + "N801", + "N802", + "N803", + "N804", + "N805", + "N806", + "N807", + "N81", + "N811", + "N812", + "N813", + "N814", + "N815", + "N816", + "N817", + "N818", + "PD", + "PD0", + "PD00", + "PD002", + "PD003", + "PD004", + "PD007", + "PD008", + "PD009", + "PD01", + "PD010", + "PD011", + "PD012", + "PD013", + "PD015", + "PD9", + "PD90", + "PD901", + "PDV", + "PDV0", + "PDV002", + "PDV003", + "PDV004", + "PDV007", + "PDV008", + "PDV009", + "PDV01", + "PDV010", + "PDV011", + "PDV012", + "PDV013", + "PDV015", + "PDV9", + "PDV90", + "PDV901", + "PGH", + "PGH0", + "PGH00", + "PGH001", + "PGH002", + "PGH003", + "PLC", + "PLC0", + "PLC04", + "PLC041", + "PLC0414", + "PLC2", + "PLC22", + "PLC220", + "PLC2201", + "PLC3", + "PLC30", + "PLC300", + "PLC3002", + "PLE", + "PLE0", + "PLE01", + "PLE011", + "PLE0117", + "PLE0118", + "PLE1", + "PLE11", + "PLE114", + "PLE1142", + "PLR", + "PLR0", + "PLR02", + "PLR020", + "PLR0206", + "PLR04", + "PLR040", + "PLR0402", + "PLR1", + "PLR17", + "PLR170", + "PLR1701", + "PLR172", + "PLR1722", + "PLW", + "PLW0", + "PLW01", + "PLW012", + "PLW0120", + "PLW06", + "PLW060", + "PLW0602", + "Q", + "Q0", + "Q00", + "Q000", + "Q001", + "Q002", + "Q003", + "R", + "R5", + "R50", + "R501", + "R502", + "R503", + "R504", + "R505", + "R506", + "R507", + "R508", + "RET", + "RET5", + "RET50", + "RET501", + "RET502", + "RET503", + "RET504", + "RET505", + "RET506", + "RET507", + "RET508", + "RUF", + "RUF0", + "RUF00", + "RUF001", + "RUF002", + "RUF003", + "RUF1", + "RUF10", + "RUF100", + "S", + "S1", + "S10", + "S101", + "S102", + "S104", + "S105", + "S106", + "S107", + "SIM", + "SIM1", + "SIM11", + "SIM118", + "T", + "T1", + "T10", + "T100", + "T2", + "T20", + "T201", + "T203", + "TID", + "TID2", + "TID25", + "TID252", + "U", + "U0", + "U00", + "U001", + "U003", + "U004", + "U005", + "U006", + "U007", + "U008", + "U009", + "U01", + "U010", + "U011", + "U012", + "U013", + "U014", + "U015", + "U016", + "U017", + "UP", + "UP0", + "UP00", + "UP001", + "UP003", + "UP004", + "UP005", + "UP006", + "UP007", + "UP008", + "UP009", + "UP01", + "UP010", + "UP011", + "UP012", + "UP013", + "UP014", + "UP015", + "UP016", + "UP017", + "UP018", + "W", + "W2", + "W29", + "W292", + "W6", + "W60", + "W605", + "YTT", + "YTT1", + "YTT10", + "YTT101", + "YTT102", + "YTT103", + "YTT2", + "YTT20", + "YTT201", + "YTT202", + "YTT203", + "YTT204", + "YTT3", + "YTT30", + "YTT301", + "YTT302", + "YTT303" + ] + }, + "Flake8AnnotationsOptions": { + "type": "object", + "properties": { + "allow-star-arg-any": { + "description": "Whether to suppress `ANN401` for dynamically typed `*args` and `**kwargs` arguments.", + "type": [ + "boolean", + "null" + ] + }, + "mypy-init-return": { + "description": "Whether to allow the omission of a return type hint for `__init__` if at least one argument is annotated.", + "type": [ + "boolean", + "null" + ] + }, + "suppress-dummy-args": { + "description": "Whether to suppress `ANN000`-level errors for arguments matching the \"dummy\" variable regex (like `_`).", + "type": [ + "boolean", + "null" + ] + }, + "suppress-none-returning": { + "description": "Whether to suppress `ANN200`-level errors 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" + ] + } + }, + "additionalProperties": false + }, + "Flake8BugbearOptions": { + "type": "object", + "properties": { + "extend-immutable-calls": { + "description": "Additional callable functions to consider \"immutable\" when evaluating, e.g., `no-mutable-default-argument` checks (`B006`).", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "Flake8ErrMsgOptions": { + "type": "object", + "properties": { + "max-string-length": { + "description": "Maximum string length for string literals in exception messages.", + "type": [ + "integer", + "null" + ], + "format": "uint", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "Flake8ImportConventionsOptions": { + "type": "object", + "properties": { + "aliases": { + "description": "The conventional aliases for imports. These aliases can be extended by the `extend_aliases` option.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "extend-aliases": { + "description": "A mapping of modules to their conventional import aliases. These aliases will be added to the `aliases` mapping.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "Flake8QuotesOptions": { + "type": "object", + "properties": { + "avoid-escape": { + "description": "Whether to avoid using single quotes if a string contains single quotes, or vice-versa with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes). This minimizes the need to escape quotation marks within strings.", + "type": [ + "boolean", + "null" + ] + }, + "docstring-quotes": { + "description": "Quote style to prefer for docstrings (either \"single\" (`'`) or \"double\" (`\"`)).", + "anyOf": [ + { + "$ref": "#/definitions/Quote" + }, + { + "type": "null" + } + ] + }, + "inline-quotes": { + "description": "Quote style to prefer for inline strings (either \"single\" (`'`) or \"double\" (`\"`)).", + "anyOf": [ + { + "$ref": "#/definitions/Quote" + }, + { + "type": "null" + } + ] + }, + "multiline-quotes": { + "description": "Quote style to prefer for multiline strings (either \"single\" (`'`) or \"double\" (`\"`)).", + "anyOf": [ + { + "$ref": "#/definitions/Quote" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "Flake8TidyImportsOptions": { + "type": "object", + "properties": { + "ban-relative-imports": { + "description": "Whether to ban all relative imports (`\"all\"`), or only those imports that extend into the parent module and beyond (`\"parents\"`).", + "anyOf": [ + { + "$ref": "#/definitions/Strictness" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "Flake8UnusedArgumentsOptions": { + "type": "object", + "properties": { + "ignore-variadic-names": { + "description": "Whether to allow unused variadic arguments, like `*args` and `**kwargs`.", + "type": [ + "boolean", + "null" + ] + } + }, + "additionalProperties": false + }, + "IsortOptions": { + "type": "object", + "properties": { + "combine-as-imports": { + "description": "Combines as imports on the same line. See isort's [`combine-as-imports`](https://pycqa.github.io/isort/docs/configuration/options.html#combine-as-imports) option.", + "type": [ + "boolean", + "null" + ] + }, + "extra-standard-library": { + "description": "A list of modules to consider standard-library, in addition to those known to Ruff in advance.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "force-wrap-aliases": { + "description": "Force `import from` statements with multiple members and at least one alias (e.g., `import A as B`) to wrap such that every line contains exactly one member. For example, this formatting would be retained, rather than condensing to a single line:\n\n```py from .utils import ( test_directory as test_directory, test_id as test_id ) ```\n\nNote that this setting is only effective when combined with `combine-as-imports = true`. When `combine-as-imports` isn't enabled, every aliased `import from` will be given its own line, in which case, wrapping is not necessary.", + "type": [ + "boolean", + "null" + ] + }, + "known-first-party": { + "description": "A list of modules to consider first-party, regardless of whether they can be identified as such via introspection of the local filesystem.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "known-third-party": { + "description": "A list of modules to consider third-party, regardless of whether they can be identified as such via introspection of the local filesystem.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "McCabeOptions": { + "type": "object", + "properties": { + "max-complexity": { + "description": "The maximum McCabe complexity to allow before triggering `C901` errors.", + "type": [ + "integer", + "null" + ], + "format": "uint", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "Pep8NamingOptions": { + "type": "object", + "properties": { + "classmethod-decorators": { + "description": "A list of decorators that, when applied to a method, indicate that the method should be treated as a class method. For example, Ruff will expect that any method decorated by a decorator in this list takes a `cls` argument as its first argument.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "ignore-names": { + "description": "A list of names to ignore when considering `pep8-naming` violations.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "staticmethod-decorators": { + "description": "A list of decorators that, when applied to a method, indicate that the method should be treated as a static method. For example, Ruff will expect that any method decorated by a decorator in this list has no `self` or `cls` argument.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "PyUpgradeOptions": { + "type": "object", + "properties": { + "keep-runtime-typing": { + "description": "Whether to avoid PEP 585 (`List[int]` -> `list[int]`) and PEP 604 (`Optional[str]` -> `str | None`) rewrites even if a file imports `from __future__ import annotations`. Note that this setting is only applicable when the target Python version is below 3.9 and 3.10 respectively.", + "type": [ + "boolean", + "null" + ] + } + }, + "additionalProperties": false + }, + "PythonVersion": { + "type": "string", + "enum": [ + "py33", + "py34", + "py35", + "py36", + "py37", + "py38", + "py39", + "py310", + "py311" + ] + }, + "Quote": { + "type": "string", + "enum": [ + "single", + "double" + ] + }, + "SerializationFormat": { + "type": "string", + "enum": [ + "text", + "json", + "junit", + "grouped", + "github" + ] + }, + "Strictness": { + "type": "string", + "enum": [ + "parents", + "all" + ] + } + } +} \ No newline at end of file diff --git a/ruff_dev/Cargo.toml b/ruff_dev/Cargo.toml index 1205f1625c..9999bed3c9 100644 --- a/ruff_dev/Cargo.toml +++ b/ruff_dev/Cargo.toml @@ -14,5 +14,7 @@ ruff = { path = ".." } rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" } rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" } rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" } +schemars = { version = "0.8.11" } +serde_json = {version="1.0.91"} strum = { version = "0.24.1", features = ["strum_macros"] } strum_macros = { version = "0.24.3" } diff --git a/ruff_dev/src/generate_check_code_prefix.rs b/ruff_dev/src/generate_check_code_prefix.rs index 8c50eee1d5..c8bbc6cd16 100644 --- a/ruff_dev/src/generate_check_code_prefix.rs +++ b/ruff_dev/src/generate_check_code_prefix.rs @@ -65,7 +65,8 @@ pub fn main(cli: &Cli) -> Result<()> { .derive("Ord") .derive("Clone") .derive("Serialize") - .derive("Deserialize"); + .derive("Deserialize") + .derive("JsonSchema"); for prefix in prefix_to_codes.keys() { gen = gen.push_variant(Variant::new(prefix.to_string())); } @@ -138,8 +139,7 @@ pub fn main(cli: &Cli) -> Result<()> { _ => panic!("Invalid prefix: {prefix}"), }; gen = gen.line(format!( - "CheckCodePrefix::{prefix} => SuffixLength::{},", - specificity + "CheckCodePrefix::{prefix} => SuffixLength::{specificity}," )); } gen.line("}"); @@ -152,6 +152,8 @@ pub fn main(cli: &Cli) -> Result<()> { output.push('\n'); output.push_str("use colored::Colorize;"); output.push('\n'); + output.push_str("use schemars::JsonSchema;"); + output.push('\n'); output.push_str("use serde::{Deserialize, Serialize};"); output.push('\n'); output.push_str("use strum_macros::{AsRefStr, EnumString};"); diff --git a/ruff_dev/src/generate_json_schema.rs b/ruff_dev/src/generate_json_schema.rs new file mode 100644 index 0000000000..fe825402df --- /dev/null +++ b/ruff_dev/src/generate_json_schema.rs @@ -0,0 +1,30 @@ +use std::fs; +use std::path::PathBuf; + +use anyhow::Result; +use clap::Args; +use ruff::settings::options::Options; +use schemars::schema_for; + +#[derive(Args)] +pub struct Cli { + /// Write the generated table to stdout (rather than to `ruff.schema.json`). + #[arg(long)] + dry_run: bool, +} + +pub fn main(cli: &Cli) -> Result<()> { + let schema = schema_for!(Options); + let schema_string = serde_json::to_string_pretty(&schema).unwrap(); + + if cli.dry_run { + println!("{schema_string}"); + } else { + let file = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("Failed to find root directory") + .join("ruff.schema.json"); + fs::write(file, schema_string.as_bytes())?; + } + Ok(()) +} diff --git a/ruff_dev/src/lib.rs b/ruff_dev/src/lib.rs index a2ab257f63..577ea5d301 100644 --- a/ruff_dev/src/lib.rs +++ b/ruff_dev/src/lib.rs @@ -12,6 +12,7 @@ )] pub mod generate_check_code_prefix; +pub mod generate_json_schema; pub mod generate_options; pub mod generate_rules_table; pub mod generate_source_code; diff --git a/ruff_dev/src/main.rs b/ruff_dev/src/main.rs index 7a91cd775e..fbcbda5d19 100644 --- a/ruff_dev/src/main.rs +++ b/ruff_dev/src/main.rs @@ -14,8 +14,8 @@ use anyhow::Result; use clap::{Parser, Subcommand}; use ruff_dev::{ - generate_check_code_prefix, generate_options, generate_rules_table, generate_source_code, - print_ast, print_cst, print_tokens, + generate_check_code_prefix, generate_json_schema, generate_options, generate_rules_table, + generate_source_code, print_ast, print_cst, print_tokens, }; #[derive(Parser)] @@ -30,6 +30,8 @@ struct Cli { enum Commands { /// Generate the `CheckCodePrefix` enum. GenerateCheckCodePrefix(generate_check_code_prefix::Cli), + /// Generate JSON schema for the TOML configuration file. + GenerateJSONSchema(generate_json_schema::Cli), /// Generate a Markdown-compatible table of supported lint rules. GenerateRulesTable(generate_rules_table::Cli), /// Generate a Markdown-compatible listing of configuration options. @@ -48,6 +50,7 @@ fn main() -> Result<()> { let cli = Cli::parse(); match &cli.command { Commands::GenerateCheckCodePrefix(args) => generate_check_code_prefix::main(args)?, + Commands::GenerateJSONSchema(args) => generate_json_schema::main(args)?, Commands::GenerateRulesTable(args) => generate_rules_table::main(args)?, Commands::GenerateSourceCode(args) => generate_source_code::main(args)?, Commands::GenerateOptions(args) => generate_options::main(args)?, diff --git a/ruff_macros/src/lib.rs b/ruff_macros/src/lib.rs index e4d6b45c17..2ef22a5aad 100644 --- a/ruff_macros/src/lib.rs +++ b/ruff_macros/src/lib.rs @@ -13,13 +13,14 @@ use quote::{quote, quote_spanned}; use syn::parse::{Parse, ParseStream}; +use syn::spanned::Spanned; use syn::token::Comma; use syn::{ parse_macro_input, AngleBracketedGenericArguments, Attribute, Data, DataStruct, DeriveInput, Field, Fields, Lit, LitStr, Path, PathArguments, PathSegment, Token, Type, TypePath, }; -#[proc_macro_derive(ConfigurationOptions, attributes(option, option_group))] +#[proc_macro_derive(ConfigurationOptions, attributes(option, doc, option_group))] pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -39,11 +40,28 @@ fn derive_impl(input: DeriveInput) -> syn::Result { let mut output = vec![]; for field in fields.named.iter() { - if let Some(attr) = field.attrs.iter().find(|a| a.path.is_ident("option")) { - output.push(handle_option(field, attr)?); + let docs: Vec<&Attribute> = field + .attrs + .iter() + .filter(|attr| attr.path.is_ident("doc")) + .collect(); + + if docs.is_empty() { + return Err(syn::Error::new( + field.span(), + "Missing documentation for field", + )); + } + + if let Some(attr) = field.attrs.iter().find(|attr| attr.path.is_ident("option")) { + output.push(handle_option(field, attr, docs)?); }; - if field.attrs.iter().any(|a| a.path.is_ident("option_group")) { + if field + .attrs + .iter() + .any(|attr| attr.path.is_ident("option_group")) + { output.push(handle_option_group(field)?); }; } @@ -70,8 +88,10 @@ fn derive_impl(input: DeriveInput) -> syn::Result { /// deriving `ConfigurationOptions`, create code that calls retrieves options /// from that group: `Foobar::get_available_options()` fn handle_option_group(field: &Field) -> syn::Result { - // unwrap is safe because we're only going over named fields - let ident = field.ident.as_ref().unwrap(); + let ident = field + .ident + .as_ref() + .expect("Expected to handle named fields"); match &field.ty { Type::Path(TypePath { @@ -103,17 +123,49 @@ fn handle_option_group(field: &Field) -> syn::Result { } } +/// Parse a `doc` attribute into it a string literal. +fn parse_doc(doc: &Attribute) -> syn::Result { + let doc = doc + .parse_meta() + .map_err(|e| syn::Error::new(doc.span(), e))?; + + match doc { + syn::Meta::NameValue(syn::MetaNameValue { + lit: Lit::Str(lit_str), + .. + }) => Ok(lit_str.value()), + _ => Err(syn::Error::new(doc.span(), "Expected doc attribute.")), + } +} + /// Parse an `#[option(doc="...", default="...", value_type="...", /// example="...")]` attribute and return data in the form of an `OptionField`. -fn handle_option(field: &Field, attr: &Attribute) -> syn::Result { - // unwrap is safe because we're only going over named fields - let ident = field.ident.as_ref().unwrap(); +fn handle_option( + field: &Field, + attr: &Attribute, + docs: Vec<&Attribute>, +) -> syn::Result { + // Convert the list of `doc` attributes into a single string. + let doc = textwrap::dedent( + &docs + .into_iter() + .map(parse_doc) + .collect::>>()? + .join("\n"), + ) + .trim_matches('\n') + .to_string(); + + let ident = field + .ident + .as_ref() + .expect("Expected to handle named fields"); let FieldAttributes { - doc, default, value_type, example, + .. } = attr.parse_args::()?; let kebab_name = LitStr::new(&ident.to_string().replace('_', "-"), ident.span()); @@ -130,7 +182,6 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result syn::Result { - let doc = _parse_key_value(input, "doc")?; - input.parse::()?; let default = _parse_key_value(input, "default")?; input.parse::()?; let value_type = _parse_key_value(input, "value_type")?; @@ -150,7 +199,6 @@ impl Parse for FieldAttributes { } Ok(FieldAttributes { - doc: textwrap::dedent(&doc).trim_matches('\n').to_string(), default, value_type, example: textwrap::dedent(&example).trim_matches('\n').to_string(), diff --git a/src/checks_gen.rs b/src/checks_gen.rs index 8f3011c083..79d0aafb51 100644 --- a/src/checks_gen.rs +++ b/src/checks_gen.rs @@ -1,6 +1,7 @@ //! File automatically generated by `examples/generate_check_code_prefix.rs`. use colored::Colorize; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use strum_macros::{AsRefStr, EnumString}; @@ -8,7 +9,17 @@ use crate::checks::CheckCode; use crate::one_time_warning; #[derive( - EnumString, AsRefStr, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize, + EnumString, + AsRefStr, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Clone, + Serialize, + Deserialize, + JsonSchema, )] pub enum CheckCodePrefix { A, diff --git a/src/flake8_annotations/settings.rs b/src/flake8_annotations/settings.rs index ee20c38c6b..e9d3dde248 100644 --- a/src/flake8_annotations/settings.rs +++ b/src/flake8_annotations/settings.rs @@ -1,51 +1,53 @@ //! Settings for the `flake-annotations` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8AnnotationsOptions" +)] pub struct Options { #[option( - doc = r#" - Whether to allow the omission of a return type hint for `__init__` if at least one - argument is annotated. - "#, default = "false", value_type = "bool", example = "mypy-init-return = true" )] + /// Whether to allow the omission of a return type hint for `__init__` if at + /// least one argument is annotated. pub mypy_init_return: Option, #[option( - doc = r#" - Whether to suppress `ANN000`-level errors for arguments matching the "dummy" variable - regex (like `_`). - "#, default = "false", value_type = "bool", example = "suppress-dummy-args = true" )] + /// Whether to suppress `ANN000`-level errors for arguments matching the + /// "dummy" variable regex (like `_`). pub suppress_dummy_args: Option, #[option( - doc = r#" - Whether to suppress `ANN200`-level errors for functions that meet either of the - following criteria: - - - Contain no `return` statement. - - Explicit `return` statement(s) all return `None` (explicitly or implicitly). - "#, default = "false", value_type = "bool", example = "suppress-none-returning = true" )] + /// Whether to suppress `ANN200`-level errors for functions that meet either + /// of the following criteria: + /// + /// - Contain no `return` statement. + /// - Explicit `return` statement(s) all return `None` (explicitly or + /// implicitly). pub suppress_none_returning: Option, #[option( - doc = "Whether to suppress `ANN401` for dynamically typed `*args` and `**kwargs` \ - arguments.", default = "false", value_type = "bool", example = "allow-star-arg-any = true" )] + /// Whether to suppress `ANN401` for dynamically typed `*args` and + /// `**kwargs` arguments. pub allow_star_arg_any: Option, } diff --git a/src/flake8_bugbear/settings.rs b/src/flake8_bugbear/settings.rs index 8aba44e74d..a2a22841ef 100644 --- a/src/flake8_bugbear/settings.rs +++ b/src/flake8_bugbear/settings.rs @@ -1,16 +1,19 @@ //! Settings for the `flake8-bugbear` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8BugbearOptions" +)] pub struct Options { #[option( - doc = r#" - Additional callable functions to consider "immutable" when evaluating, e.g., - `no-mutable-default-argument` checks (`B006`). - "#, default = r#"[]"#, value_type = "Vec", example = r#" @@ -18,6 +21,8 @@ pub struct Options { extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"] "# )] + /// Additional callable functions to consider "immutable" when evaluating, + /// e.g., `no-mutable-default-argument` checks (`B006`). pub extend_immutable_calls: Option>, } diff --git a/src/flake8_errmsg/settings.rs b/src/flake8_errmsg/settings.rs index 02e94f111f..1288ba66f6 100644 --- a/src/flake8_errmsg/settings.rs +++ b/src/flake8_errmsg/settings.rs @@ -1,19 +1,24 @@ //! Settings for the `flake8-errmsg` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8ErrMsgOptions" +)] pub struct Options { #[option( - doc = r#" - Maximum string length for string literals in exception messages. - "#, default = "0", value_type = "usize", example = "max-string-length = 20" )] + /// Maximum string length for string literals in exception messages. pub max_string_length: Option, } diff --git a/src/flake8_import_conventions/settings.rs b/src/flake8_import_conventions/settings.rs index e2ec838ffd..264c1c3f40 100644 --- a/src/flake8_import_conventions/settings.rs +++ b/src/flake8_import_conventions/settings.rs @@ -5,6 +5,7 @@ use std::hash::{Hash, Hasher}; use itertools::Itertools; use ruff_macros::ConfigurationOptions; use rustc_hash::FxHashMap; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; const CONVENTIONAL_ALIASES: &[(&str, &str)] = &[ @@ -15,12 +16,16 @@ const CONVENTIONAL_ALIASES: &[(&str, &str)] = &[ ("seaborn", "sns"), ]; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8ImportConventionsOptions" +)] pub struct Options { #[option( - doc = "The conventional aliases for imports. These aliases can be extended by the \ - `extend_aliases` option.", default = r#"{"altair": "alt", "matplotlib.pyplot": "plt", "numpy": "np", "pandas": "pd", "seaborn": "sns"}"#, value_type = "FxHashMap", example = r#" @@ -32,10 +37,10 @@ pub struct Options { seaborn = "sns" "# )] + /// The conventional aliases for imports. These aliases can be extended by + /// the `extend_aliases` option. pub aliases: Option>, #[option( - doc = "A mapping of modules to their conventional import aliases. These aliases will be \ - added to the `aliases` mapping.", default = r#"{}"#, value_type = "FxHashMap", example = r#" @@ -43,6 +48,8 @@ pub struct Options { "dask.dataframe" = "dd" "# )] + /// A mapping of modules to their conventional import aliases. These aliases + /// will be added to the `aliases` mapping. pub extend_aliases: Option>, } diff --git a/src/flake8_quotes/settings.rs b/src/flake8_quotes/settings.rs index 5a75f795ce..ae17f1b4dd 100644 --- a/src/flake8_quotes/settings.rs +++ b/src/flake8_quotes/settings.rs @@ -1,57 +1,56 @@ //! Settings for the `flake8-quotes` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] pub enum Quote { Single, Double, } -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8QuotesOptions" +)] pub struct Options { #[option( - doc = r#" - Quote style to prefer for inline strings (either "single" (`'`) or "double" (`"`)). - "#, default = r#""double""#, value_type = "Quote", example = r#" inline-quotes = "single" "# )] + /// Quote style to prefer for inline strings (either "single" (`'`) or + /// "double" (`"`)). pub inline_quotes: Option, #[option( - doc = r#" - Quote style to prefer for multiline strings (either "single" (`'`) or "double" (`"`)). - "#, default = r#""double""#, value_type = "Quote", example = r#" multiline-quotes = "single" "# )] + /// Quote style to prefer for multiline strings (either "single" (`'`) or + /// "double" (`"`)). pub multiline_quotes: Option, #[option( - doc = r#" - Quote style to prefer for docstrings (either "single" (`'`) or "double" (`"`)). - "#, default = r#""double""#, value_type = "Quote", example = r#" docstring-quotes = "single" "# )] + /// Quote style to prefer for docstrings (either "single" (`'`) or "double" + /// (`"`)). pub docstring_quotes: Option, #[option( - doc = r#" - Whether to avoid using single quotes if a string contains single quotes, or vice-versa - with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes). - This minimizes the need to escape quotation marks within strings. - "#, default = r#"true"#, value_type = "bool", example = r#" @@ -59,6 +58,9 @@ pub struct Options { avoid-escape = false "# )] + /// Whether to avoid using single quotes if a string contains single quotes, + /// or vice-versa with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes). + /// This minimizes the need to escape quotation marks within strings. pub avoid_escape: Option, } diff --git a/src/flake8_tidy_imports/settings.rs b/src/flake8_tidy_imports/settings.rs index 25354527b6..7a6baa6615 100644 --- a/src/flake8_tidy_imports/settings.rs +++ b/src/flake8_tidy_imports/settings.rs @@ -1,23 +1,26 @@ //! Settings for the `flake8-tidy-imports` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] pub enum Strictness { Parents, All, } -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8TidyImportsOptions" +)] pub struct Options { #[option( - doc = r#" - Whether to ban all relative imports (`"all"`), or only those imports that extend into - the parent module and beyond (`"parents"`). - "#, default = r#""parents""#, value_type = "Strictness", example = r#" @@ -25,6 +28,8 @@ pub struct Options { ban-relative-imports = "all" "# )] + /// Whether to ban all relative imports (`"all"`), or only those imports + /// that extend into the parent module and beyond (`"parents"`). pub ban_relative_imports: Option, } diff --git a/src/flake8_unused_arguments/settings.rs b/src/flake8_unused_arguments/settings.rs index 5fa3081aca..06c0ee26b3 100644 --- a/src/flake8_unused_arguments/settings.rs +++ b/src/flake8_unused_arguments/settings.rs @@ -1,19 +1,24 @@ //! Settings for the `flake8-unused-arguments` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8UnusedArgumentsOptions" +)] pub struct Options { #[option( - doc = r#" - Whether to allow unused variadic arguments, like `*args` and `**kwargs`. - "#, default = "false", value_type = "bool", example = "ignore-variadic-names = true" )] + /// Whether to allow unused variadic arguments, like `*args` and `**kwargs`. pub ignore_variadic_names: Option, } diff --git a/src/isort/settings.rs b/src/isort/settings.rs index a64f81bef0..112664af84 100644 --- a/src/isort/settings.rs +++ b/src/isort/settings.rs @@ -3,40 +3,19 @@ use std::collections::BTreeSet; use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "IsortOptions" +)] pub struct Options { #[option( - doc = r#" - Combines as imports on the same line. See isort's [`combine-as-imports`](https://pycqa.github.io/isort/docs/configuration/options.html#combine-as-imports) - option. - "#, - default = r#"false"#, - value_type = "bool", - example = r#" - combine-as-imports = true - "# - )] - pub combine_as_imports: Option, - #[option( - doc = r#" - Force `import from` statements with multiple members and at least one alias (e.g., - `import A as B`) to wrap such that every line contains exactly one member. For example, - this formatting would be retained, rather than condensing to a single line: - - ```py - from .utils import ( - test_directory as test_directory, - test_id as test_id - ) - ``` - - Note that this setting is only effective when combined with `combine-as-imports = true`. - When `combine-as-imports` isn't enabled, every aliased `import from` will be given its - own line, in which case, wrapping is not necessary. - "#, default = r#"false"#, value_type = "bool", example = r#" @@ -44,42 +23,62 @@ pub struct Options { combine-as-imports = true "# )] + /// Force `import from` statements with multiple members and at least one + /// alias (e.g., `import A as B`) to wrap such that every line contains + /// exactly one member. For example, this formatting would be retained, + /// rather than condensing to a single line: + /// + /// ```py + /// from .utils import ( + /// test_directory as test_directory, + /// test_id as test_id + /// ) + /// ``` + /// + /// Note that this setting is only effective when combined with + /// `combine-as-imports = true`. When `combine-as-imports` isn't + /// enabled, every aliased `import from` will be given its own line, in + /// which case, wrapping is not necessary. pub force_wrap_aliases: Option, #[option( - doc = r#" - A list of modules to consider first-party, regardless of whether they can be identified - as such via introspection of the local filesystem. - "#, + default = r#"false"#, + value_type = "bool", + example = r#" + combine-as-imports = true + "# + )] + /// Combines as imports on the same line. See isort's [`combine-as-imports`](https://pycqa.github.io/isort/docs/configuration/options.html#combine-as-imports) + /// option. + pub combine_as_imports: Option, + #[option( default = r#"[]"#, value_type = "Vec", example = r#" known-first-party = ["src"] "# )] + /// A list of modules to consider first-party, regardless of whether they + /// can be identified as such via introspection of the local filesystem. pub known_first_party: Option>, #[option( - doc = r#" - A list of modules to consider third-party, regardless of whether they can be identified - as such via introspection of the local filesystem. - "#, default = r#"[]"#, value_type = "Vec", example = r#" known-third-party = ["src"] "# )] + /// A list of modules to consider third-party, regardless of whether they + /// can be identified as such via introspection of the local filesystem. pub known_third_party: Option>, #[option( - doc = r#" - A list of modules to consider standard-library, in addition to those known to Ruff in - advance. - "#, default = r#"[]"#, value_type = "Vec", example = r#" extra-standard-library = ["path"] "# )] + /// A list of modules to consider standard-library, in addition to those + /// known to Ruff in advance. pub extra_standard_library: Option>, } diff --git a/src/mccabe/settings.rs b/src/mccabe/settings.rs index d00c607ce7..d5eed62d8a 100644 --- a/src/mccabe/settings.rs +++ b/src/mccabe/settings.rs @@ -1,13 +1,19 @@ //! Settings for the `mccabe` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "McCabeOptions" +)] pub struct Options { #[option( - doc = "The maximum McCabe complexity to allow before triggering `C901` errors.", default = "10", value_type = "usize", example = r#" @@ -15,6 +21,7 @@ pub struct Options { max-complexity = 5 "# )] + /// The maximum McCabe complexity to allow before triggering `C901` errors. pub max_complexity: Option, } diff --git a/src/pep8_naming/settings.rs b/src/pep8_naming/settings.rs index 6fd3c19f83..7193e154f8 100644 --- a/src/pep8_naming/settings.rs +++ b/src/pep8_naming/settings.rs @@ -1,6 +1,7 @@ //! Settings for the `pep8-naming` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; const IGNORE_NAMES: [&str; 12] = [ @@ -22,26 +23,25 @@ const CLASSMETHOD_DECORATORS: [&str; 1] = ["classmethod"]; const STATICMETHOD_DECORATORS: [&str; 1] = ["staticmethod"]; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Pep8NamingOptions" +)] pub struct Options { #[option( - doc = r#" - A list of names to ignore when considering `pep8-naming` violations. - "#, default = r#"["setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule", "asyncSetUp", "asyncTearDown", "setUpTestData", "failureException", "longMessage", "maxDiff"]"#, value_type = "Vec", example = r#" ignore-names = ["callMethod"] "# )] + /// A list of names to ignore when considering `pep8-naming` violations. pub ignore_names: Option>, #[option( - doc = r#" - A list of decorators that, when applied to a method, indicate that the method should be - treated as a class method. For example, Ruff will expect that any method decorated by a - decorator in this list takes a `cls` argument as its first argument. - "#, default = r#"["classmethod"]"#, value_type = "Vec", example = r#" @@ -49,13 +49,12 @@ pub struct Options { classmethod-decorators = ["classmethod", "pydantic.validator"] "# )] + /// A list of decorators that, when applied to a method, indicate that the + /// method should be treated as a class method. For example, Ruff will + /// expect that any method decorated by a decorator in this list takes a + /// `cls` argument as its first argument. pub classmethod_decorators: Option>, #[option( - doc = r#" - A list of decorators that, when applied to a method, indicate that the method should be - treated as a static method. For example, Ruff will expect that any method decorated by a - decorator in this list has no `self` or `cls` argument. - "#, default = r#"["staticmethod"]"#, value_type = "Vec", example = r#" @@ -63,6 +62,10 @@ pub struct Options { staticmethod-decorators = ["staticmethod", "stcmthd"] "# )] + /// A list of decorators that, when applied to a method, indicate that the + /// method should be treated as a static method. For example, Ruff will + /// expect that any method decorated by a decorator in this list has no + /// `self` or `cls` argument. pub staticmethod_decorators: Option>, } diff --git a/src/pyupgrade/settings.rs b/src/pyupgrade/settings.rs index 459c82eb9e..d5586c80c7 100644 --- a/src/pyupgrade/settings.rs +++ b/src/pyupgrade/settings.rs @@ -1,15 +1,19 @@ //! Settings for the `pyupgrade` plugin. use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "PyUpgradeOptions" +)] pub struct Options { #[option( - doc = r#" - Whether to avoid PEP 585 (`List[int]` -> `list[int]`) and PEP 604 (`Optional[str]` -> `str | None`) rewrites even if a file imports `from __future__ import annotations`. Note that this setting is only applicable when the target Python version is below 3.9 and 3.10 respectively. - "#, default = r#"false"#, value_type = "bool", example = r#" @@ -17,6 +21,11 @@ pub struct Options { keep-runtime-typing = true "# )] + /// Whether to avoid PEP 585 (`List[int]` -> `list[int]`) and PEP 604 + /// (`Optional[str]` -> `str | None`) rewrites even if a file imports `from + /// __future__ import annotations`. Note that this setting is only + /// applicable when the target Python version is below 3.9 and 3.10 + /// respectively. pub keep_runtime_typing: Option, } diff --git a/src/settings/options.rs b/src/settings/options.rs index ffb11818f9..5fc9d43338 100644 --- a/src/settings/options.rs +++ b/src/settings/options.rs @@ -2,6 +2,7 @@ use ruff_macros::ConfigurationOptions; use rustc_hash::FxHashMap; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::checks_gen::CheckCodePrefix; @@ -11,14 +12,12 @@ use crate::{ flake8_tidy_imports, flake8_unused_arguments, isort, mccabe, pep8_naming, pyupgrade, }; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)] +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] pub struct Options { #[option( - doc = r#" - A list of allowed "confusable" Unicode characters to ignore when enforcing `RUF001`, - `RUF002`, and `RUF003`. - "#, default = r#"[]"#, value_type = "Vec", example = r#" @@ -27,13 +26,10 @@ pub struct Options { allowed-confusables = ["−", "ρ", "∗"] "# )] + /// A list of allowed "confusable" Unicode characters to ignore when + /// enforcing `RUF001`, `RUF002`, and `RUF003`. pub allowed_confusables: Option>, #[option( - doc = r#" - A regular expression used to identify "dummy" variables, or those which should be - ignored when evaluating (e.g.) unused-variable checks. The default expression matches - `_`, `__`, and `_var`, but not `_var_`. - "#, default = r#""^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$""#, value_type = "Regex", example = r#" @@ -41,39 +37,33 @@ pub struct Options { dummy-variable-rgx = "^_$" "# )] + /// A regular expression used to identify "dummy" variables, or those which + /// should be ignored when evaluating (e.g.) unused-variable checks. The + /// default expression matches `_`, `__`, and `_var`, but not `_var_`. pub dummy_variable_rgx: Option, #[option( - doc = r#" - 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 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`). - - Note that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify - the excluded paths. - "#, default = r#"[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]"#, value_type = "Vec", example = r#" exclude = [".venv"] "# )] + /// 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 + /// 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`). + /// + /// Note that you'll typically want to use + /// [`extend-exclude`](#extend-exclude) to modify the excluded paths. pub exclude: Option>, #[option( - doc = r#" - A path to a local `pyproject.toml` file to merge into this configuration. User home - directory and environment variables will be expanded. - - To resolve the current `pyproject.toml` file, Ruff will first resolve this base - configuration file, then merge in any properties defined in the current configuration - file. - "#, default = r#"None"#, value_type = "Path", example = r#" @@ -83,10 +73,15 @@ pub struct Options { line-length = 100 "# )] + /// A path to a local `pyproject.toml` file to merge into this + /// configuration. User home directory and environment variables will be + /// expanded. + /// + /// To resolve the current `pyproject.toml` file, Ruff will first resolve + /// this base configuration file, then merge in any properties defined + /// in the current configuration file. pub extend: Option, #[option( - doc = "A list of file patterns to omit from linting, in addition to those specified by \ - `exclude`.", default = "[]", value_type = "Vec", example = r#" @@ -94,10 +89,10 @@ pub struct Options { extend-exclude = ["tests", "src/bad.py"] "# )] + /// A list of file patterns to omit from linting, in addition to those + /// specified by `exclude`. pub extend_exclude: Option>, #[option( - doc = "A list of check code prefixes to ignore, in addition to those specified by \ - `ignore`.", default = "[]", value_type = "Vec", example = r#" @@ -105,10 +100,10 @@ pub struct Options { extend-ignore = ["F841"] "# )] + /// A list of check code prefixes to ignore, in addition to those specified + /// by `ignore`. pub extend_ignore: Option>, #[option( - doc = "A list of check code prefixes to enable, in addition to those specified by \ - `select`.", default = "[]", value_type = "Vec", example = r#" @@ -116,13 +111,10 @@ pub struct Options { extend-select = ["B", "Q"] "# )] + /// A list of check code prefixes to enable, in addition to those specified + /// by `select`. pub extend_select: Option>, #[option( - doc = r#" - A list of check codes that are unsupported by Ruff, but should be preserved when (e.g.) - validating `# noqa` directives. Useful for retaining `# noqa` directives that cover plugins not - yet implemented in Ruff. - "#, default = "[]", value_type = "Vec", example = r#" @@ -131,19 +123,16 @@ pub struct Options { external = ["V101"] "# )] + /// A list of check codes that are unsupported by Ruff, but should be + /// preserved when (e.g.) validating `# noqa` directives. Useful for + /// retaining `# noqa` directives that cover plugins not yet implemented + /// in Ruff. pub external: Option>, - #[option( - doc = r#" - Enable autofix behavior by-default when running `ruff` (overridden - by the `--fix` and `--no-fix` command-line flags). - "#, - default = "false", - value_type = "bool", - example = "fix = true" - )] + #[option(default = "false", value_type = "bool", example = "fix = true")] + /// Enable autofix behavior by-default when running `ruff` (overridden + /// by the `--fix` and `--no-fix` command-line flags). pub fix: Option, #[option( - doc = "A list of check code prefixes to consider autofix-able.", default = r#"["A", "ANN", "ARG", "B", "BLE", "C", "D", "E", "ERA", "F", "FBT", "I", "ICN", "N", "PGH", "PLC", "PLE", "PLR", "PLW", "Q", "RET", "RUF", "S", "T", "TID", "UP", "W", "YTT"]"#, value_type = "Vec", example = r#" @@ -151,13 +140,9 @@ pub struct Options { fixable = ["E", "F"] "# )] + /// A list of check code prefixes to consider autofix-able. pub fixable: Option>, #[option( - doc = r#" - The style in which violation messages should be formatted: `"text"` (default), - `"grouped"` (group messages by file), `"json"` (machine-readable), `"junit"` - (machine-readable XML), or `"github"` (GitHub Actions annotations). - "#, default = r#""text""#, value_type = "SerializationType", example = r#" @@ -165,33 +150,30 @@ pub struct Options { format = "grouped" "# )] + /// The style in which violation messages should be formatted: `"text"` + /// (default), `"grouped"` (group messages by file), `"json"` + /// (machine-readable), `"junit"` (machine-readable XML), or `"github"` + /// (GitHub Actions annotations). pub format: Option, #[option( - doc = r#" - Whether to enforce `exclude` and `extend-exclude` patterns, even for paths that are - passed to Ruff explicitly. Typically, Ruff will lint any paths passed in directly, even - if they would typically be excluded. Setting `force-exclude = true` will cause Ruff to - respect these exclusions unequivocally. - - This is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all - changed files to the [`ruff-pre-commit`](https://github.com/charliermarsh/ruff-pre-commit) - plugin, regardless of whether they're marked as excluded by Ruff's own settings. - "#, default = r#"false"#, value_type = "bool", example = r#" force-exclude = true "# )] + /// Whether to enforce `exclude` and `extend-exclude` patterns, even for + /// paths that are passed to Ruff explicitly. Typically, Ruff will lint + /// any paths passed in directly, even if they would typically be + /// excluded. Setting `force-exclude = true` will cause Ruff to + /// respect these exclusions unequivocally. + /// + /// This is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all + /// changed files to the [`ruff-pre-commit`](https://github.com/charliermarsh/ruff-pre-commit) + /// plugin, regardless of whether they're marked as excluded by Ruff's own + /// settings. pub force_exclude: Option, #[option( - doc = r" - A list of check code prefixes to ignore. Prefixes can specify exact checks (like - `F841`), entire categories (like `F`), or anything in between. - - When breaking ties between enabled and disabled checks (via `select` and `ignore`, - respectively), more specific prefixes override less specific prefixes. - ", default = "[]", value_type = "Vec", example = r#" @@ -199,23 +181,28 @@ pub struct Options { ignore = ["F841"] "# )] + /// A list of check code prefixes to ignore. Prefixes can specify exact + /// checks (like `F841`), entire categories (like `F`), or anything in + /// between. + /// + /// When breaking ties between enabled and disabled checks (via `select` and + /// `ignore`, respectively), more specific prefixes override less + /// specific prefixes. pub ignore: Option>, #[option( - doc = r#" - Avoid automatically removing unused imports in `__init__.py` files. Such imports will - still be +flagged, but with a dedicated message suggesting that the import is either - added to the module' +`__all__` symbol, or re-exported with a redundant alias (e.g., - `import os as os`). - "#, default = "false", value_type = "bool", example = r#" ignore-init-module-imports = true "# )] + /// Avoid automatically removing unused imports in `__init__.py` files. Such + /// imports will still be +flagged, but with a dedicated message + /// suggesting that the import is either added to the module' +`__all__` + /// symbol, or re-exported with a redundant alias (e.g., `import os as + /// os`). pub ignore_init_module_imports: Option, #[option( - doc = "The line length to use when enforcing long-lines violations (like E501).", default = "88", value_type = "usize", example = r#" @@ -223,27 +210,21 @@ pub struct Options { line-length = 120 "# )] + /// The line length to use when enforcing long-lines violations (like + /// `E501`). pub line_length: Option, #[option( - doc = r#" - Whether to automatically exclude files that are ignored by `.ignore`, `.gitignore`, - `.git/info/exclude`, and global `gitignore` files. Enabled by default. - "#, default = "true", value_type = "bool", example = r#" respect_gitignore = false "# )] + /// Whether to automatically exclude files that are ignored by `.ignore`, + /// `.gitignore`, `.git/info/exclude`, and global `gitignore` files. + /// Enabled by default. pub respect_gitignore: Option, #[option( - doc = r#" - A list of check code prefixes to enable. Prefixes can specify exact checks (like - `F841`), entire categories (like `F`), or anything in between. - - When breaking ties between enabled and disabled checks (via `select` and `ignore`, - respectively), more specific prefixes override less specific prefixes. - "#, default = r#"["E", "F"]"#, value_type = "Vec", example = r#" @@ -251,12 +232,15 @@ pub struct Options { select = ["E", "F", "B", "Q"] "# )] + /// A list of check code prefixes to enable. Prefixes can specify exact + /// checks (like `F841`), entire categories (like `F`), or anything in + /// between. + /// + /// When breaking ties between enabled and disabled checks (via `select` and + /// `ignore`, respectively), more specific prefixes override less + /// specific prefixes. pub select: Option>, #[option( - doc = r#" - Whether to show source code snippets when reporting lint error violations (overridden by - the `--show-source` command-line flag). - "#, default = "false", value_type = "bool", example = r#" @@ -264,31 +248,10 @@ pub struct Options { show-source = true "# )] + /// Whether to show source code snippets when reporting lint error + /// violations (overridden by the `--show-source` command-line flag). pub show_source: Option, #[option( - doc = r#" - The source code paths to consider, e.g., when resolving first- vs. third-party imports. - - As an example: given a Python package structure like: - - ```text - my_package/ - pyproject.toml - src/ - my_package/ - __init__.py - foo.py - bar.py - ``` - - The `src` directory should be included in `source` (e.g., `source = ["src"]`), such that - when resolving imports, `my_package.foo` is considered a first-party import. - - This field supports globs. For example, if you have a series of Python packages in - a `python_modules` directory, `src = ["python_modules/*"]` would expand to incorporate - all of the packages in that directory. User home directory and environment variables - will also be expanded. - "#, default = r#"["."]"#, value_type = "Vec", example = r#" @@ -296,13 +259,32 @@ pub struct Options { src = ["src", "test"] "# )] + /// The source code paths to consider, e.g., when resolving first- vs. + /// third-party imports. + /// + /// As an example: given a Python package structure like: + /// + /// ```text + /// my_package/ + /// pyproject.toml + /// src/ + /// my_package/ + /// __init__.py + /// foo.py + /// bar.py + /// ``` + /// + /// The `src` directory should be included in `source` (e.g., `source = + /// ["src"]`), such that when resolving imports, `my_package.foo` is + /// considered a first-party import. + /// + /// This field supports globs. For example, if you have a series of Python + /// packages in a `python_modules` directory, `src = + /// ["python_modules/*"]` would expand to incorporate all of the + /// packages in that directory. User home directory and environment + /// variables will also be expanded. pub src: Option>, #[option( - doc = r#" - The Python version to target, e.g., when considering automatic code upgrades, like - rewriting type annotations. Note that the target version will _not_ be inferred from the - _current_ Python version, and instead must be specified explicitly (as seen below). - "#, default = r#""py310""#, value_type = "PythonVersion", example = r#" @@ -310,9 +292,12 @@ pub struct Options { target-version = "py37" "# )] + /// The Python version to target, e.g., when considering automatic code + /// upgrades, like rewriting type annotations. Note that the target + /// version will _not_ be inferred from the _current_ Python version, + /// and instead must be specified explicitly (as seen below). pub target_version: Option, #[option( - doc = "A list of check code prefixes to consider un-autofix-able.", default = "[]", value_type = "Vec", example = r#" @@ -320,53 +305,60 @@ pub struct Options { unfixable = ["F401"] "# )] + /// A list of check code prefixes to consider un-autofix-able. pub unfixable: Option>, #[option( - doc = r#" - A path to the cache directory. - - By default, Ruff stores cache results in a `.ruff_cache` directory in the current - project root. - - However, Ruff will also respect the `RUFF_CACHE_DIR` environment variable, which takes - precedence over that default. - - This setting will override even the `RUFF_CACHE_DIR` environment variable, if set. - "#, default = ".ruff_cache", value_type = "PathBuf", example = r#"cache-dir = "~/.cache/ruff""# )] + /// A path to the cache directory. + /// + /// By default, Ruff stores cache results in a `.ruff_cache` directory in + /// the current project root. + /// + /// However, Ruff will also respect the `RUFF_CACHE_DIR` environment + /// variable, which takes precedence over that default. + /// + /// This setting will override even the `RUFF_CACHE_DIR` environment + /// variable, if set. pub cache_dir: Option, - // Plugins + /// Plugins #[option_group] + /// Options for the `flake8-annotations` plugin. pub flake8_annotations: Option, #[option_group] + /// Options for the `flake8-bugbear` plugin. pub flake8_bugbear: Option, #[option_group] + /// Options for the `flake8-errmsg` plugin. pub flake8_errmsg: Option, #[option_group] + /// Options for the `flake8-quotes` plugin. pub flake8_quotes: Option, #[option_group] + /// Options for the `flake8-tidy-imports` plugin. pub flake8_tidy_imports: Option, #[option_group] + /// Options for the `flake8-import-conventions` plugin. pub flake8_import_conventions: Option, #[option_group] + /// Options for the `flake8-unused-arguments` plugin. pub flake8_unused_arguments: Option, #[option_group] + /// Options for the `isort` plugin. pub isort: Option, #[option_group] + /// Options for the `mccabe` plugin. pub mccabe: Option, #[option_group] + /// Options for the `pep8-naming` plugin. pub pep8_naming: Option, #[option_group] + /// Options for the `pyupgrade` plugin. pub pyupgrade: Option, // Tables are required to go last. #[option( - doc = r#" - A list of mappings from file pattern to check code prefixes to exclude, when considering - any matching files. - "#, default = "{}", value_type = "HashMap>", example = r#" @@ -376,5 +368,7 @@ pub struct Options { "path/to/file.py" = ["E402"] "# )] + /// A list of mappings from file pattern to check code prefixes to exclude, + /// when considering any matching files. pub per_file_ignores: Option>>, } diff --git a/src/settings/types.rs b/src/settings/types.rs index 095e80d5ca..25aefce70e 100644 --- a/src/settings/types.rs +++ b/src/settings/types.rs @@ -7,13 +7,16 @@ use anyhow::{anyhow, bail, Result}; use clap::ValueEnum; use globset::{Glob, GlobSetBuilder}; use rustc_hash::FxHashSet; +use schemars::JsonSchema; use serde::{de, Deserialize, Deserializer, Serialize}; use crate::checks::CheckCode; use crate::checks_gen::CheckCodePrefix; use crate::fs; -#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[derive( + Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema, +)] #[serde(rename_all = "lowercase")] pub enum PythonVersion { Py33, @@ -142,7 +145,7 @@ impl FromStr for PatternPrefixPair { } } -#[derive(Clone, Copy, ValueEnum, PartialEq, Eq, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, ValueEnum, PartialEq, Eq, Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "kebab-case")] pub enum SerializationFormat { Text,