mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:53 +00:00
Make setting and retrieving pydocstyle settings less tedious (#12582)
This commit is contained in:
parent
138e70bd5c
commit
83b1c48a93
14 changed files with 146 additions and 134 deletions
|
@ -1,14 +1,11 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
use ruff_python_ast::name::QualifiedName;
|
||||
use ruff_python_semantic::{Definition, SemanticModel};
|
||||
use ruff_source_file::UniversalNewlines;
|
||||
|
||||
use crate::docstrings::sections::{SectionContexts, SectionKind};
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::rules::pydocstyle::settings::Convention;
|
||||
use crate::rules::pydocstyle::settings::{Convention, Settings};
|
||||
|
||||
/// Return the index of the first logical line in a string.
|
||||
pub(super) fn logical_line(content: &str) -> Option<usize> {
|
||||
|
@ -45,10 +42,12 @@ pub(super) fn ends_with_backslash(line: &str) -> bool {
|
|||
/// Check decorator list to see if function should be ignored.
|
||||
pub(crate) fn should_ignore_definition(
|
||||
definition: &Definition,
|
||||
ignore_decorators: &BTreeSet<String>,
|
||||
settings: &Settings,
|
||||
semantic: &SemanticModel,
|
||||
) -> bool {
|
||||
if ignore_decorators.is_empty() {
|
||||
let ignore_decorators = settings.ignore_decorators();
|
||||
|
||||
if ignore_decorators.len() == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -61,15 +60,15 @@ pub(crate) fn should_ignore_definition(
|
|||
.resolve_qualified_name(map_callable(&decorator.expression))
|
||||
.is_some_and(|qualified_name| {
|
||||
ignore_decorators
|
||||
.iter()
|
||||
.any(|decorator| QualifiedName::from_dotted_name(decorator) == qualified_name)
|
||||
.clone()
|
||||
.any(|decorator| decorator == qualified_name)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_section_contexts<'a>(
|
||||
docstring: &'a Docstring<'a>,
|
||||
convention: Option<&'a Convention>,
|
||||
convention: Option<Convention>,
|
||||
) -> SectionContexts<'a> {
|
||||
match convention {
|
||||
Some(Convention::Google) => {
|
||||
|
|
|
@ -5,7 +5,6 @@ pub mod settings;
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
@ -98,13 +97,11 @@ mod tests {
|
|||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle").join(path).as_path(),
|
||||
&settings::LinterSettings {
|
||||
pydocstyle: Settings {
|
||||
convention: None,
|
||||
ignore_decorators: BTreeSet::from_iter(["functools.wraps".to_string()]),
|
||||
property_decorators: BTreeSet::from_iter([
|
||||
"gi.repository.GObject.Property".to_string()
|
||||
]),
|
||||
},
|
||||
pydocstyle: Settings::new(
|
||||
None,
|
||||
["functools.wraps".to_string()],
|
||||
["gi.repository.GObject.Property".to_string()],
|
||||
),
|
||||
..settings::LinterSettings::for_rule(rule_code)
|
||||
},
|
||||
)?;
|
||||
|
@ -129,11 +126,7 @@ mod tests {
|
|||
&settings::LinterSettings {
|
||||
// When inferring the convention, we'll see a few false negatives.
|
||||
// See: https://github.com/PyCQA/pydocstyle/issues/459.
|
||||
pydocstyle: Settings {
|
||||
convention: None,
|
||||
ignore_decorators: BTreeSet::new(),
|
||||
property_decorators: BTreeSet::new(),
|
||||
},
|
||||
pydocstyle: Settings::default(),
|
||||
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
|
||||
},
|
||||
)?;
|
||||
|
@ -147,11 +140,7 @@ mod tests {
|
|||
Path::new("pydocstyle/D417.py"),
|
||||
&settings::LinterSettings {
|
||||
// With explicit Google convention, we should flag every function.
|
||||
pydocstyle: Settings {
|
||||
convention: Some(Convention::Google),
|
||||
ignore_decorators: BTreeSet::new(),
|
||||
property_decorators: BTreeSet::new(),
|
||||
},
|
||||
pydocstyle: Settings::new(Some(Convention::Google), [], []),
|
||||
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
|
||||
},
|
||||
)?;
|
||||
|
@ -164,12 +153,8 @@ mod tests {
|
|||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/D417.py"),
|
||||
&settings::LinterSettings {
|
||||
// With explicit Google convention, we shouldn't flag anything.
|
||||
pydocstyle: Settings {
|
||||
convention: Some(Convention::Numpy),
|
||||
ignore_decorators: BTreeSet::new(),
|
||||
property_decorators: BTreeSet::new(),
|
||||
},
|
||||
// With explicit numpy convention, we shouldn't flag anything.
|
||||
pydocstyle: Settings::new(Some(Convention::Numpy), [], []),
|
||||
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
|
||||
},
|
||||
)?;
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use imperative::Mood;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::name::QualifiedName;
|
||||
use ruff_python_semantic::analyze::visibility::{is_property, is_test};
|
||||
use ruff_source_file::UniversalNewlines;
|
||||
use ruff_text_size::Ranged;
|
||||
|
@ -13,6 +10,7 @@ use ruff_text_size::Ranged;
|
|||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::rules::pydocstyle::helpers::normalize_word;
|
||||
use crate::rules::pydocstyle::settings::Settings;
|
||||
|
||||
static MOOD: Lazy<Mood> = Lazy::new(Mood::new);
|
||||
|
||||
|
@ -66,24 +64,21 @@ impl Violation for NonImperativeMood {
|
|||
pub(crate) fn non_imperative_mood(
|
||||
checker: &mut Checker,
|
||||
docstring: &Docstring,
|
||||
property_decorators: &BTreeSet<String>,
|
||||
settings: &Settings,
|
||||
) {
|
||||
let Some(function) = docstring.definition.as_function_def() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let property_decorators = property_decorators
|
||||
.iter()
|
||||
.map(|decorator| QualifiedName::from_dotted_name(decorator))
|
||||
.collect::<Vec<QualifiedName>>();
|
||||
if is_test(&function.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if is_test(&function.name)
|
||||
|| is_property(
|
||||
&function.decorator_list,
|
||||
&property_decorators,
|
||||
checker.semantic(),
|
||||
)
|
||||
{
|
||||
if is_property(
|
||||
&function.decorator_list,
|
||||
settings.property_decorators(),
|
||||
checker.semantic(),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1325,7 +1325,7 @@ pub(crate) fn sections(
|
|||
checker: &mut Checker,
|
||||
docstring: &Docstring,
|
||||
section_contexts: &SectionContexts,
|
||||
convention: Option<&Convention>,
|
||||
convention: Option<Convention>,
|
||||
) {
|
||||
match convention {
|
||||
Some(Convention::Google) => parse_google_sections(checker, docstring, section_contexts),
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::display_settings;
|
||||
use ruff_macros::CacheKey;
|
||||
use ruff_python_ast::name::QualifiedName;
|
||||
|
||||
use crate::display_settings;
|
||||
use crate::registry::Rule;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, CacheKey)]
|
||||
|
@ -85,9 +87,36 @@ impl fmt::Display for Convention {
|
|||
|
||||
#[derive(Debug, Clone, Default, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub convention: Option<Convention>,
|
||||
pub ignore_decorators: BTreeSet<String>,
|
||||
pub property_decorators: BTreeSet<String>,
|
||||
convention: Option<Convention>,
|
||||
ignore_decorators: BTreeSet<String>,
|
||||
property_decorators: BTreeSet<String>,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
convention: Option<Convention>,
|
||||
ignore_decorators: impl IntoIterator<Item = String>,
|
||||
property_decorators: impl IntoIterator<Item = String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
convention,
|
||||
ignore_decorators: ignore_decorators.into_iter().collect(),
|
||||
property_decorators: property_decorators.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convention(&self) -> Option<Convention> {
|
||||
self.convention
|
||||
}
|
||||
|
||||
pub fn ignore_decorators(&self) -> DecoratorIterator {
|
||||
DecoratorIterator::new(&self.ignore_decorators)
|
||||
}
|
||||
|
||||
pub fn property_decorators(&self) -> DecoratorIterator {
|
||||
DecoratorIterator::new(&self.property_decorators)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Settings {
|
||||
|
@ -104,3 +133,34 @@ impl fmt::Display for Settings {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DecoratorIterator<'a> {
|
||||
decorators: std::collections::btree_set::Iter<'a, String>,
|
||||
}
|
||||
|
||||
impl<'a> DecoratorIterator<'a> {
|
||||
fn new(decorators: &'a BTreeSet<String>) -> Self {
|
||||
Self {
|
||||
decorators: decorators.iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for DecoratorIterator<'a> {
|
||||
type Item = QualifiedName<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<QualifiedName<'a>> {
|
||||
self.decorators
|
||||
.next()
|
||||
.map(|deco| QualifiedName::from_dotted_name(deco))
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for DecoratorIterator<'_> {}
|
||||
|
||||
impl ExactSizeIterator for DecoratorIterator<'_> {
|
||||
fn len(&self) -> usize {
|
||||
self.decorators.len()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue