Skip to content

Commit

Permalink
Automatically linkify option references in rule documentation
Browse files Browse the repository at this point in the history
Previously the rule documentation referenced configuration options
via full https:// URLs, which was bad for several reasons:

* changing the website would mean you'd have to change all URLs
* the links didn't work when building mkdocs locally
* the URLs showed up in the `ruff rule` output
* broken references weren't detected by our CI

This commit solves all of these problems by post-processing the
Markdown, recognizing sections such as:

    ## Options

    * `flake8-tidy-imports.ban-relative-imports`

`cargo dev generate-all` will automatically linkify such references
and panic if the referenced option doesn't exist.
Note that the option can also be linked in the other Markdown sections
via e.g. [`flake8-tidy-imports.ban-relative-imports`] since
the post-processing code generates a CommonMark link definition.

Resolves #2766.
  • Loading branch information
not-my-profile authored and charliermarsh committed Feb 12, 2023
1 parent fc4c927 commit 28c9263
Show file tree
Hide file tree
Showing 13 changed files with 122 additions and 41 deletions.
7 changes: 3 additions & 4 deletions crates/ruff/src/rules/flake8_no_pep420/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ define_violation!(
/// `__init__.py` file is typically meant to be a regular package, and
/// the absence of the `__init__.py` file is probably an oversight.
///
/// Note that namespace packages can be specified via the
/// [`namespace-packages`](https://github.com/charliermarsh/ruff#namespace-packages)
/// configuration option. Adding a namespace package to the configuration
/// will suppress this violation for a given package.
/// ## Options
///
/// * `namespace-packages`
pub struct ImplicitNamespacePackage {
pub filename: String,
}
Expand Down
21 changes: 16 additions & 5 deletions crates/ruff/src/rules/flake8_quotes/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ use crate::violation::AlwaysAutofixableViolation;
define_violation!(
/// ## What it does
/// Checks for inline strings that use single quotes or double quotes,
/// depending on the value of the [`inline-quotes`](https://github.com/charliermarsh/ruff#inline-quotes)
/// setting.
/// depending on the value of the [`flake8-quotes.inline-quotes`] option.
///
/// ## Why is this bad?
/// Consistency is good. Use either single or double quotes for inline
/// strings, but be consistent.
///
/// ## Options
///
/// * `flake8-quotes.inline-quotes`
///
/// ## Example
/// ```python
/// foo = 'bar'
Expand Down Expand Up @@ -56,13 +59,17 @@ impl AlwaysAutofixableViolation for BadQuotesInlineString {
define_violation!(
/// ## What it does
/// Checks for multiline strings that use single quotes or double quotes,
/// depending on the value of the [`multiline-quotes`](https://github.com/charliermarsh/ruff#multiline-quotes)
/// depending on the value of the [`flake8-quotes.multiline-quotes`]
/// setting.
///
/// ## Why is this bad?
/// Consistency is good. Use either single or double quotes for multiline
/// strings, but be consistent.
///
/// ## Options
///
/// * `flake8-quotes.multiline-quotes`
///
/// ## Example
/// ```python
/// foo = '''
Expand Down Expand Up @@ -101,13 +108,17 @@ impl AlwaysAutofixableViolation for BadQuotesMultilineString {

define_violation!(
/// ## What it does
/// Checks for docstrings that use single quotes or double quotes, depending on the value of the [`docstring-quotes`](https://github.com/charliermarsh/ruff#docstring-quotes)
/// setting.
/// Checks for docstrings that use single quotes or double quotes, depending
/// on the value of the [`flake8-quotes.docstring-quotes`] setting.
///
/// ## Why is this bad?
/// Consistency is good. Use either single or double quotes for docstring
/// strings, but be consistent.
///
/// ## Options
///
/// * `flake8-quotes.docstring-quotes`
///
/// ## Example
/// ```python
/// '''
Expand Down
8 changes: 3 additions & 5 deletions crates/ruff/src/rules/flake8_tidy_imports/relative_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,9 @@ define_violation!(
/// > from .sibling import example
/// > ```
///
/// Note that degree of strictness packages can be specified via the
/// [`ban-relative-imports`](https://github.com/charliermarsh/ruff#ban-relative-imports)
/// configuration option, which allows banning all relative imports
/// (`ban-relative-imports = "all"`) or only those that extend into the parent module or beyond
/// (`ban-relative-imports = "parents"`, the default).
/// ## Options
///
/// * `flake8-tidy-imports.ban-relative-imports`
///
/// ## Example
/// ```python
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff/src/rules/mccabe/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ define_violation!(
/// ## Why is this bad?
/// Functions with a high complexity are hard to understand and maintain.
///
/// ## Options
///
/// * `mccabe.max-complexity`
///
/// ## Example
/// ```python
/// def foo(a, b, c):
Expand Down
10 changes: 7 additions & 3 deletions crates/ruff/src/rules/pyflakes/rules/unused_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@ define_violation!(
/// A variable that is defined but not used is likely a mistake, and should be
/// removed to avoid confusion.
///
/// If a variable is intentionally defined-but-not-used, it should be prefixed
/// with an underscore, or some other value that adheres to the
/// [`dummy-variable-rgx`](https://github.com/charliermarsh/ruff#dummy-variable-rgx) pattern.
/// If a variable is intentionally defined-but-not-used, it should be
/// prefixed with an underscore, or some other value that adheres to the
/// [`dummy-variable-rgx`] pattern.
///
/// ## Options
///
/// * `dummy-variable-rgx`
///
/// ## Example
/// ```python
Expand Down
36 changes: 35 additions & 1 deletion crates/ruff_dev/src/generate_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::fs;

use anyhow::Result;
use ruff::registry::{Linter, Rule, RuleNamespace};
use ruff::settings::options::Options;
use ruff::settings::options_base::ConfigurationOptions;
use ruff::AutofixAvailability;
use strum::IntoEnumIterator;

Expand Down Expand Up @@ -37,7 +39,7 @@ pub fn main(args: &Args) -> Result<()> {
output.push('\n');
}

output.push_str(explanation.trim());
process_documentation(explanation.trim(), &mut output);

if args.dry_run {
println!("{output}");
Expand All @@ -49,3 +51,35 @@ pub fn main(args: &Args) -> Result<()> {
}
Ok(())
}

fn process_documentation(documentation: &str, out: &mut String) {
let mut in_options = false;
let mut after = String::new();

for line in documentation.split_inclusive('\n') {
if line.starts_with("## ") {
in_options = line == "## Options\n";
} else if in_options {
if let Some(rest) = line.strip_prefix("* `") {
let option = rest.trim_end().trim_end_matches('`');

assert!(
Options::get(Some(option)).is_some(),
"unknown option {option}"
);

let anchor = option.rsplit('.').next().unwrap();
out.push_str(&format!("* [`{option}`]\n"));
after.push_str(&format!("[`{option}`]: ../../settings#{anchor}"));

continue;
}
}

out.push_str(line);
}
if !after.is_empty() {
out.push_str("\n\n");
out.push_str(&after);
}
}
12 changes: 9 additions & 3 deletions docs/rules/bad-quotes-docstring.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ Derived from the **flake8-quotes** linter.
Autofix is always available.

## What it does
Checks for docstrings that use single quotes or double quotes, depending on the value of the [`docstring-quotes`](https://github.com/charliermarsh/ruff#docstring-quotes)
setting.
Checks for docstrings that use single quotes or double quotes, depending
on the value of the [`flake8-quotes.docstring-quotes`] setting.

## Why is this bad?
Consistency is good. Use either single or double quotes for docstring
strings, but be consistent.

## Options

* [`flake8-quotes.docstring-quotes`]

## Example
```python
'''
Expand All @@ -24,4 +28,6 @@ Assuming `docstring-quotes` is set to `double`, use instead:
"""
bar
"""
```
```

[`flake8-quotes.docstring-quotes`]: ../../settings#docstring-quotes
11 changes: 8 additions & 3 deletions docs/rules/bad-quotes-inline-string.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ Autofix is always available.

## What it does
Checks for inline strings that use single quotes or double quotes,
depending on the value of the [`inline-quotes`](https://github.com/charliermarsh/ruff#inline-quotes)
setting.
depending on the value of the [`flake8-quotes.inline-quotes`] option.

## Why is this bad?
Consistency is good. Use either single or double quotes for inline
strings, but be consistent.

## Options

* [`flake8-quotes.inline-quotes`]

## Example
```python
foo = 'bar'
Expand All @@ -21,4 +24,6 @@ foo = 'bar'
Assuming `inline-quotes` is set to `double`, use instead:
```python
foo = "bar"
```
```

[`flake8-quotes.inline-quotes`]: ../../settings#inline-quotes
10 changes: 8 additions & 2 deletions docs/rules/bad-quotes-multiline-string.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ Autofix is always available.

## What it does
Checks for multiline strings that use single quotes or double quotes,
depending on the value of the [`multiline-quotes`](https://github.com/charliermarsh/ruff#multiline-quotes)
depending on the value of the [`flake8-quotes.multiline-quotes`]
setting.

## Why is this bad?
Consistency is good. Use either single or double quotes for multiline
strings, but be consistent.

## Options

* [`flake8-quotes.multiline-quotes`]

## Example
```python
foo = '''
Expand All @@ -25,4 +29,6 @@ Assuming `multiline-quotes` is set to `double`, use instead:
foo = """
bar
"""
```
```

[`flake8-quotes.multiline-quotes`]: ../../settings#multiline-quotes
8 changes: 7 additions & 1 deletion docs/rules/complex-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ the code where the program has a choice of two or more paths to follow.
## Why is this bad?
Functions with a high complexity are hard to understand and maintain.

## Options

* [`mccabe.max-complexity`]

## Example
```python
def foo(a, b, c):
Expand All @@ -38,4 +42,6 @@ def foo(a, b, c):
if not c:
return 2
return 1
```
```

[`mccabe.max-complexity`]: ../../settings#max-complexity
10 changes: 6 additions & 4 deletions docs/rules/implicit-namespace-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Namespace packages are less widely used, so a package that lacks an
`__init__.py` file is typically meant to be a regular package, and
the absence of the `__init__.py` file is probably an oversight.

Note that namespace packages can be specified via the
[`namespace-packages`](https://github.com/charliermarsh/ruff#namespace-packages)
configuration option. Adding a namespace package to the configuration
will suppress this violation for a given package.
## Options

* [`namespace-packages`]


[`namespace-packages`]: ../../settings#namespace-packages
12 changes: 6 additions & 6 deletions docs/rules/relative-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ Absolute imports, or relative imports from siblings, are recommended by [PEP 8](
> from .sibling import example
> ```
Note that degree of strictness packages can be specified via the
[`ban-relative-imports`](https://github.com/charliermarsh/ruff#ban-relative-imports)
configuration option, which allows banning all relative imports
(`ban-relative-imports = "all"`) or only those that extend into the parent module or beyond
(`ban-relative-imports = "parents"`, the default).
## Options
* [`flake8-tidy-imports.ban-relative-imports`]
## Example
```python
Expand All @@ -38,4 +36,6 @@ from .. import foo
Use instead:
```python
from mypkg import foo
```
```

[`flake8-tidy-imports.ban-relative-imports`]: ../../settings#ban-relative-imports
14 changes: 10 additions & 4 deletions docs/rules/unused-variable.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ Checks for the presence of unused variables in function scopes.
A variable that is defined but not used is likely a mistake, and should be
removed to avoid confusion.

If a variable is intentionally defined-but-not-used, it should be prefixed
with an underscore, or some other value that adheres to the
[`dummy-variable-rgx`](https://github.com/charliermarsh/ruff#dummy-variable-rgx) pattern.
If a variable is intentionally defined-but-not-used, it should be
prefixed with an underscore, or some other value that adheres to the
[`dummy-variable-rgx`] pattern.

## Options

* [`dummy-variable-rgx`]

## Example
```python
Expand All @@ -28,4 +32,6 @@ Use instead:
def foo():
x = 1
return x
```
```

[`dummy-variable-rgx`]: ../../settings#dummy-variable-rgx

0 comments on commit 28c9263

Please sign in to comment.