Skip to content

Commit

Permalink
Promote lint. settings over top-level settings (#9476)
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Jan 29, 2024
1 parent 0045032 commit e94f0f8
Show file tree
Hide file tree
Showing 62 changed files with 388 additions and 309 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ else:
```

## Options
- `pyflakes.extend-generics`
- `lint.pyflakes.extend-generics`

## References
- [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement)
Expand Down
18 changes: 9 additions & 9 deletions crates/ruff_dev/src/generate_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ fn process_documentation(documentation: &str, out: &mut String, rule_name: &str)
}
}

let anchor = option.replace('.', "-");
let anchor = option.replace('.', "_");
out.push_str(&format!("- [`{option}`][{option}]\n"));
after.push_str(&format!("[{option}]: ../settings.md#{anchor}\n"));

Expand All @@ -142,13 +142,13 @@ mod tests {
let mut output = String::new();
process_documentation(
"
See also [`mccabe.max-complexity`] and [`task-tags`].
See also [`lint.mccabe.max-complexity`] and [`lint.task-tags`].
Something [`else`][other].
## Options
- `task-tags`
- `mccabe.max-complexity`
- `lint.task-tags`
- `lint.mccabe.max-complexity`
[other]: http://example.com.",
&mut output,
Expand All @@ -157,18 +157,18 @@ Something [`else`][other].
assert_eq!(
output,
"
See also [`mccabe.max-complexity`][mccabe.max-complexity] and [`task-tags`][task-tags].
See also [`lint.mccabe.max-complexity`][lint.mccabe.max-complexity] and [`lint.task-tags`][lint.task-tags].
Something [`else`][other].
## Options
- [`task-tags`][task-tags]
- [`mccabe.max-complexity`][mccabe.max-complexity]
- [`lint.task-tags`][lint.task-tags]
- [`lint.mccabe.max-complexity`][lint.mccabe.max-complexity]
[other]: http://example.com.
[task-tags]: ../settings.md#task-tags
[mccabe.max-complexity]: ../settings.md#mccabe-max-complexity
[lint.task-tags]: ../settings.md#lint_task-tags
[lint.mccabe.max-complexity]: ../settings.md#lint_mccabe_max-complexity
"
);
}
Expand Down
158 changes: 69 additions & 89 deletions crates/ruff_dev/src/generate_options.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Generate a Markdown-compatible listing of configuration options for `pyproject.toml`.
//!
//! Used for <https://docs.astral.sh/ruff/settings/>.
use itertools::Itertools;
use std::fmt::Write;

use ruff_python_trivia::textwrap;
Expand All @@ -9,16 +10,29 @@ use ruff_workspace::options_base::{OptionField, OptionSet, OptionsMetadata, Visi

pub(crate) fn generate() -> String {
let mut output = String::new();
generate_set(&mut output, &Set::Toplevel(Options::metadata()));

generate_set(
&mut output,
Set::Toplevel(Options::metadata()),
&mut Vec::new(),
);

output
}

fn generate_set(output: &mut String, set: &Set) {
if set.level() < 2 {
writeln!(output, "### {title}\n", title = set.title()).unwrap();
} else {
writeln!(output, "#### {title}\n", title = set.title()).unwrap();
fn generate_set(output: &mut String, set: Set, parents: &mut Vec<Set>) {
match &set {
Set::Toplevel(_) => {
output.push_str("### Top-level\n");
}
Set::Named { name, .. } => {
let title = parents
.iter()
.filter_map(|set| set.name())
.chain(std::iter::once(name.as_str()))
.join(".");
writeln!(output, "#### `{title}`\n",).unwrap();
}
}

if let Some(documentation) = set.metadata().documentation() {
Expand All @@ -35,72 +49,68 @@ fn generate_set(output: &mut String, set: &Set) {
fields.sort_unstable_by(|(name, _), (name2, _)| name.cmp(name2));
sets.sort_unstable_by(|(name, _), (name2, _)| name.cmp(name2));

parents.push(set);

// Generate the fields.
for (name, field) in &fields {
emit_field(output, name, field, set);
emit_field(output, name, field, parents.as_slice());
output.push_str("---\n\n");
}

// Generate all the sub-sets.
for (set_name, sub_set) in &sets {
generate_set(output, &Set::Named(set_name, *sub_set, set.level() + 1));
generate_set(
output,
Set::Named {
name: set_name.to_string(),
set: *sub_set,
},
parents,
);
}

parents.pop();
}

enum Set<'a> {
enum Set {
Toplevel(OptionSet),
Named(&'a str, OptionSet, u32),
Named { name: String, set: OptionSet },
}

impl<'a> Set<'a> {
fn name(&self) -> Option<&'a str> {
impl Set {
fn name(&self) -> Option<&str> {
match self {
Set::Toplevel(_) => None,
Set::Named(name, _, _) => Some(name),
}
}

fn title(&self) -> &'a str {
match self {
Set::Toplevel(_) => "Top-level",
Set::Named(name, _, _) => name,
Set::Named { name, .. } => Some(name),
}
}

fn metadata(&self) -> &OptionSet {
match self {
Set::Toplevel(set) => set,
Set::Named(_, set, _) => set,
}
}

fn level(&self) -> u32 {
match self {
Set::Toplevel(_) => 0,
Set::Named(_, _, level) => *level,
Set::Named { set, .. } => set,
}
}
}

fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set: &Set) {
let header_level = if parent_set.level() < 2 {
"####"
fn emit_field(output: &mut String, name: &str, field: &OptionField, parents: &[Set]) {
let header_level = if parents.is_empty() { "####" } else { "#####" };
let parents_anchor = parents.iter().filter_map(|parent| parent.name()).join("_");

if parents_anchor.is_empty() {
output.push_str(&format!(
"{header_level} [`{name}`](#{name}) {{: #{name} }}\n"
));
} else {
"#####"
};
output.push_str(&format!(
"{header_level} [`{name}`](#{parents_anchor}_{name}) {{: #{parents_anchor}_{name} }}\n"
));

// if there's a set name, we need to add it to the anchor
if let Some(set_name) = parent_set.name() {
// the anchor used to just be the name, but now it's the group name
// for backwards compatibility, we need to keep the old anchor
output.push_str(&format!("<span id=\"{name}\"></span>\n"));

output.push_str(&format!(
"{header_level} [`{name}`](#{set_name}-{name}) {{: #{set_name}-{name} }}\n"
));
} else {
output.push_str(&format!("{header_level} [`{name}`](#{name})\n"));
}

output.push('\n');

if let Some(deprecated) = &field.deprecated {
Expand Down Expand Up @@ -129,12 +139,12 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set:
output.push_str("**Example usage**:\n\n");
output.push_str(&format_tab(
"pyproject.toml",
&format_header(field.scope, parent_set, ConfigurationFile::PyprojectToml),
&format_header(field.scope, parents, ConfigurationFile::PyprojectToml),
field.example,
));
output.push_str(&format_tab(
"ruff.toml",
&format_header(field.scope, parent_set, ConfigurationFile::RuffToml),
&format_header(field.scope, parents, ConfigurationFile::RuffToml),
field.example,
));
output.push('\n');
Expand All @@ -152,52 +162,22 @@ fn format_tab(tab_name: &str, header: &str, content: &str) -> String {
/// Format the TOML header for the example usage for a given option.
///
/// For example: `[tool.ruff.format]` or `[tool.ruff.lint.isort]`.
fn format_header(
scope: Option<&str>,
parent_set: &Set,
configuration: ConfigurationFile,
) -> String {
match configuration {
ConfigurationFile::PyprojectToml => {
let mut header = if let Some(set_name) = parent_set.name() {
if set_name == "format" {
String::from("tool.ruff.format")
} else {
format!("tool.ruff.lint.{set_name}")
}
} else {
"tool.ruff".to_string()
};
if let Some(scope) = scope {
if !header.is_empty() {
header.push('.');
}
header.push_str(scope);
}
format!("[{header}]")
}
ConfigurationFile::RuffToml => {
let mut header = if let Some(set_name) = parent_set.name() {
if set_name == "format" {
String::from("format")
} else {
format!("lint.{set_name}")
}
} else {
String::new()
};
if let Some(scope) = scope {
if !header.is_empty() {
header.push('.');
}
header.push_str(scope);
}
if header.is_empty() {
String::new()
} else {
format!("[{header}]")
}
}
fn format_header(scope: Option<&str>, parents: &[Set], configuration: ConfigurationFile) -> String {
let tool_parent = match configuration {
ConfigurationFile::PyprojectToml => Some("tool.ruff"),
ConfigurationFile::RuffToml => None,
};

let header = tool_parent
.into_iter()
.chain(parents.iter().filter_map(|parent| parent.name()))
.chain(scope)
.join(".");

if header.is_empty() {
String::new()
} else {
format!("[{header}]")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use super::super::detection::comment_contains_code;
/// ```
///
/// ## Options
/// - `task-tags`
/// - `lint.task-tags`
///
/// [#4845]: https://github.com/astral-sh/ruff/issues/4845
#[violation]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ use crate::checkers::ast::Checker;
/// calls to the function, which can lead to unexpected behaviour.
///
/// Calls can be marked as an exception to this rule with the
/// [`flake8-bugbear.extend-immutable-calls`] configuration option.
/// [`lint.flake8-bugbear.extend-immutable-calls`] configuration option.
///
/// Arguments with immutable type annotations will be ignored by this rule.
/// Types outside of the standard library can be marked as immutable with the
/// [`flake8-bugbear.extend-immutable-calls`] configuration option as well.
/// [`lint.flake8-bugbear.extend-immutable-calls`] configuration option as well.
///
/// ## Example
/// ```python
Expand Down Expand Up @@ -61,7 +61,7 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `flake8-bugbear.extend-immutable-calls`
/// - `lint.flake8-bugbear.extend-immutable-calls`
#[violation]
pub struct FunctionCallInDefaultArgument {
name: Option<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::checkers::ast::Checker;
///
/// Arguments with immutable type annotations will be ignored by this rule.
/// Types outside of the standard library can be marked as immutable with the
/// [`flake8-bugbear.extend-immutable-calls`] configuration option.
/// [`lint.flake8-bugbear.extend-immutable-calls`] configuration option.
///
/// ## Known problems
/// Mutable argument defaults can be used intentionally to cache computation
Expand Down Expand Up @@ -61,7 +61,7 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `flake8-bugbear.extend-immutable-calls`
/// - `lint.flake8-bugbear.extend-immutable-calls`
///
/// ## References
/// - [Python documentation: Default Argument Values](https://docs.python.org/3/tutorial/controlflow.html#default-argument-values)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use super::super::helpers::shadows_builtin;
/// builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
///
/// ## Example
/// ```python
Expand All @@ -44,7 +44,7 @@ use super::super::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.builtins-ignorelist`
///
/// ## References
/// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// Builtins can be marked as exceptions to this rule via the
/// [`flake8-builtins.builtins-ignorelist`] configuration option, or
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option, or
/// converted to the appropriate dunder method. Methods decorated with
/// `@typing.override` or `@typing_extensions.override` are also
/// ignored.
Expand All @@ -55,7 +55,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.builtins-ignorelist`
#[violation]
pub struct BuiltinAttributeShadowing {
kind: Kind,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
///
/// ## Example
/// ```python
Expand All @@ -41,7 +41,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.builtins-ignorelist`
///
/// ## References
/// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
Expand Down
Loading

0 comments on commit e94f0f8

Please sign in to comment.