Automatically set baseline D codes based on convention (#1574)

This commit is contained in:
Charlie Marsh 2023-01-02 19:08:56 -05:00 committed by GitHub
parent 1425b21d93
commit 0c05488740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 305 additions and 275 deletions

101
README.md
View File

@ -1466,59 +1466,49 @@ Found 3 error(s).
### Does Ruff support NumPy- or Google-style docstrings? ### Does Ruff support NumPy- or Google-style docstrings?
Yes! To enable a specific docstring convention, start by enabling all `pydocstyle` error codes, and Yes! To enable specific docstring convention, add the following to your `pyproject.toml`:
then selectively disabling based on your [preferred convention](https://www.pydocstyle.org/en/latest/error_codes.html#default-conventions).
For example, if you're coming from `flake8-docstrings`, the following configuration is equivalent to
`--docstring-convention=numpy`:
```toml ```toml
[tool.ruff] [tool.ruff.pydocstyle]
select = ["D"] convention = "google" # Accepts: "google", "numpy", or "pep257".
ignore = [
"D107",
"D203",
"D212",
"D213",
"D402",
"D413",
"D415",
"D416",
"D417",
]
``` ```
Similarly, the following is equivalent to `--docstring-convention=google`: For example, if you're coming from `flake8-docstrings`, and your originating configuration uses
`--docstring-convention=numpy`, you'd instead set `convention = "numpy"` in your `pyproject.toml`,
as above.
Note that setting a `convention` is equivalent to adding that convention's specific set of codes to
your `select`. For example, `convention = "numpy"` is equivalent to:
```toml ```toml
[tool.ruff] [tool.ruff]
select = ["D"] # Enable all `D` errors except `D107`, `D203`, `D212`, `D213`, `D402`, `D413`, `D415`, `D416`,
ignore = [ # and `D417`.
"D203", select = [
"D100",
"D101",
"D102",
"D103",
"D104",
"D105",
"D106",
"D200",
"D201",
"D202",
"D204", "D204",
"D213", "D205",
"D215", "D206",
"D400", "D207",
"D404", "D208",
"D406", "D209",
"D407", "D210",
"D408", "D211",
"D409",
"D413",
]
```
Similarly, the following is equivalent to `--docstring-convention=pep8`:
```toml
[tool.ruff]
select = ["D"]
ignore = [
"D203",
"D212",
"D213",
"D214", "D214",
"D215", "D215",
"D300",
"D301",
"D400",
"D403",
"D404", "D404",
"D405", "D405",
"D406", "D406",
@ -1527,24 +1517,16 @@ ignore = [
"D409", "D409",
"D410", "D410",
"D411", "D411",
"D413", "D412",
"D415", "D414",
"D416", "D418",
"D417", "D419",
] ]
``` ```
Note that Ruff _also_ supports a [`convention`](#convention) setting: ### How can I tell what settings Ruff is using to check my code?
```toml Run `ruff /path/to/code.py --show-settings` to view the resolved settings for a given file.
[tool.ruff.pydocstyle]
convention = "google"
```
However, this setting is purely used to implement robust detection of Google and NumPy-style
sections, and thus avoid the [false negatives](https://github.com/PyCQA/pydocstyle/issues/459) seen
in `pydocstyle`; it does not affect which errors are enabled, which is driven by the `select` and
`ignore` settings, as described above.
## Development ## Development
@ -2975,9 +2957,8 @@ staticmethod-decorators = ["staticmethod", "stcmthd"]
#### [`convention`](#convention) #### [`convention`](#convention)
Whether to use Google-style or Numpy-style conventions when detecting Whether to use Google-style or NumPy-style conventions or the PEP257
docstring sections. By default, conventions will be inferred from defaults when analyzing docstring sections.
the available sections.
**Default value**: `None` **Default value**: `None`

View File

@ -0,0 +1,43 @@
[flake8]
# Exclude the grpc generated code
exclude = ./manim/grpc/gen/*
max-complexity = 15
max-line-length = 88
statistics = True
# Prevents some flake8-rst-docstrings errors
rst-roles = attr,class,func,meth,mod,obj,ref,doc,exc
rst-directives = manim, SEEALSO, seealso
docstring-convention=numpy
select = A,A00,B,B9,C4,C90,D,E,F,F,PT,RST,SIM,W
# General Compatibility
extend-ignore = E203, W503, D202, D212, D213, D404
# Misc
F401, F403, F405, F841, E501, E731, E402, F811, F821,
# Plug-in: flake8-builtins
A001, A002, A003,
# Plug-in: flake8-bugbear
B006, B007, B008, B009, B010, B903, B950,
# Plug-in: flake8-simplify
SIM105, SIM106, SIM119,
# Plug-in: flake8-comprehensions
C901
# Plug-in: flake8-pytest-style
PT001, PT004, PT006, PT011, PT018, PT022, PT023,
# Plug-in: flake8-docstrings
D100, D101, D102, D103, D104, D105, D106, D107,
D200, D202, D204, D205, D209,
D301,
D400, D401, D402, D403, D405, D406, D407, D409, D411, D412, D414,
# Plug-in: flake8-rst-docstrings
RST201, RST203, RST210, RST212, RST213, RST215,
RST301, RST303,

View File

@ -52,6 +52,19 @@ pub fn convert(
} }
} }
// Infer plugins, if not provided.
let plugins = plugins.unwrap_or_else(|| {
let from_options = plugin::infer_plugins_from_options(flake8);
if !from_options.is_empty() {
eprintln!("Inferred plugins from settings: {from_options:#?}");
}
let from_codes = plugin::infer_plugins_from_codes(&referenced_codes);
if !from_codes.is_empty() {
eprintln!("Inferred plugins from referenced check codes: {from_codes:#?}");
}
from_options.into_iter().chain(from_codes).collect()
});
// Check if the user has specified a `select`. If not, we'll add our own // Check if the user has specified a `select`. If not, we'll add our own
// default `select`, and populate it based on user plugins. // default `select`, and populate it based on user plugins.
let mut select = flake8 let mut select = flake8
@ -61,22 +74,7 @@ pub fn convert(
.as_ref() .as_ref()
.map(|value| BTreeSet::from_iter(parser::parse_prefix_codes(value))) .map(|value| BTreeSet::from_iter(parser::parse_prefix_codes(value)))
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| plugin::resolve_select(flake8, &plugins));
plugin::resolve_select(
flake8,
&plugins.unwrap_or_else(|| {
let from_options = plugin::infer_plugins_from_options(flake8);
if !from_options.is_empty() {
eprintln!("Inferred plugins from settings: {from_options:#?}");
}
let from_codes = plugin::infer_plugins_from_codes(&referenced_codes);
if !from_codes.is_empty() {
eprintln!("Inferred plugins from referenced check codes: {from_codes:#?}");
}
from_options.into_iter().chain(from_codes).collect()
}),
)
});
let mut ignore = flake8 let mut ignore = flake8
.get("ignore") .get("ignore")
.and_then(|value| { .and_then(|value| {
@ -209,7 +207,8 @@ pub fn convert(
"docstring-convention" => match value.trim() { "docstring-convention" => match value.trim() {
"google" => pydocstyle.convention = Some(Convention::Google), "google" => pydocstyle.convention = Some(Convention::Google),
"numpy" => pydocstyle.convention = Some(Convention::Numpy), "numpy" => pydocstyle.convention = Some(Convention::Numpy),
"pep257" | "all" => pydocstyle.convention = None, "pep257" => pydocstyle.convention = Some(Convention::Pep257),
"all" => pydocstyle.convention = None,
_ => eprintln!("Unexpected '{key}' value: {value}"), _ => eprintln!("Unexpected '{key}' value: {value}"),
}, },
// mccabe // mccabe
@ -292,6 +291,13 @@ pub fn convert(
} }
} }
// Set default `convention`.
if plugins.contains(&Plugin::Flake8Docstrings) {
if pydocstyle.convention.is_none() {
pydocstyle.convention = Some(Convention::Pep257);
}
}
// Deduplicate and sort. // Deduplicate and sort.
options.select = Some(Vec::from_iter(select)); options.select = Some(Vec::from_iter(select));
options.ignore = Some(Vec::from_iter(ignore)); options.ignore = Some(Vec::from_iter(ignore));
@ -691,42 +697,6 @@ mod tests {
required_version: None, required_version: None,
respect_gitignore: None, respect_gitignore: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::D100,
CheckCodePrefix::D101,
CheckCodePrefix::D102,
CheckCodePrefix::D103,
CheckCodePrefix::D104,
CheckCodePrefix::D105,
CheckCodePrefix::D106,
CheckCodePrefix::D200,
CheckCodePrefix::D201,
CheckCodePrefix::D202,
CheckCodePrefix::D204,
CheckCodePrefix::D205,
CheckCodePrefix::D206,
CheckCodePrefix::D207,
CheckCodePrefix::D208,
CheckCodePrefix::D209,
CheckCodePrefix::D210,
CheckCodePrefix::D211,
CheckCodePrefix::D214,
CheckCodePrefix::D215,
CheckCodePrefix::D300,
CheckCodePrefix::D301,
CheckCodePrefix::D400,
CheckCodePrefix::D403,
CheckCodePrefix::D404,
CheckCodePrefix::D405,
CheckCodePrefix::D406,
CheckCodePrefix::D407,
CheckCodePrefix::D408,
CheckCodePrefix::D409,
CheckCodePrefix::D410,
CheckCodePrefix::D411,
CheckCodePrefix::D412,
CheckCodePrefix::D414,
CheckCodePrefix::D418,
CheckCodePrefix::D419,
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,

View File

@ -149,8 +149,8 @@ impl Plugin {
} }
} }
} }
// Default to PEP8. // Default to PEP257.
DocstringConvention::PEP8.select() DocstringConvention::Pep257.select()
} }
Plugin::Flake8Eradicate => vec![CheckCodePrefix::ERA], Plugin::Flake8Eradicate => vec![CheckCodePrefix::ERA],
Plugin::Flake8ErrMsg => vec![CheckCodePrefix::EM], Plugin::Flake8ErrMsg => vec![CheckCodePrefix::EM],
@ -171,8 +171,8 @@ impl Plugin {
pub enum DocstringConvention { pub enum DocstringConvention {
All, All,
PEP8, Pep257,
NumPy, Numpy,
Google, Google,
} }
@ -182,8 +182,8 @@ impl FromStr for DocstringConvention {
fn from_str(string: &str) -> Result<Self, Self::Err> { fn from_str(string: &str) -> Result<Self, Self::Err> {
match string { match string {
"all" => Ok(DocstringConvention::All), "all" => Ok(DocstringConvention::All),
"pep8" => Ok(DocstringConvention::PEP8), "pep257" => Ok(DocstringConvention::Pep257),
"numpy" => Ok(DocstringConvention::NumPy), "numpy" => Ok(DocstringConvention::Numpy),
"google" => Ok(DocstringConvention::Google), "google" => Ok(DocstringConvention::Google),
_ => Err(anyhow!("Unknown docstring convention: {string}")), _ => Err(anyhow!("Unknown docstring convention: {string}")),
} }
@ -194,151 +194,14 @@ impl DocstringConvention {
fn select(&self) -> Vec<CheckCodePrefix> { fn select(&self) -> Vec<CheckCodePrefix> {
match self { match self {
DocstringConvention::All => vec![CheckCodePrefix::D], DocstringConvention::All => vec![CheckCodePrefix::D],
DocstringConvention::PEP8 => vec![ DocstringConvention::Pep257 => vec![
// All errors except D203, D212, D213, D214, D215, D404, D405, D406, D407, D408, // Covered by the `convention` setting.
// D409, D410, D411, D413, D415, D416 and D417.
CheckCodePrefix::D100,
CheckCodePrefix::D101,
CheckCodePrefix::D102,
CheckCodePrefix::D103,
CheckCodePrefix::D104,
CheckCodePrefix::D105,
CheckCodePrefix::D106,
CheckCodePrefix::D107,
CheckCodePrefix::D200,
CheckCodePrefix::D201,
CheckCodePrefix::D202,
// CheckCodePrefix::D203,
CheckCodePrefix::D204,
CheckCodePrefix::D205,
CheckCodePrefix::D206,
CheckCodePrefix::D207,
CheckCodePrefix::D208,
CheckCodePrefix::D209,
CheckCodePrefix::D210,
CheckCodePrefix::D211,
// CheckCodePrefix::D212,
// CheckCodePrefix::D213,
// CheckCodePrefix::D214,
// CheckCodePrefix::D215,
CheckCodePrefix::D300,
CheckCodePrefix::D301,
CheckCodePrefix::D400,
CheckCodePrefix::D402,
CheckCodePrefix::D403,
// CheckCodePrefix::D404,
// CheckCodePrefix::D405,
// CheckCodePrefix::D406,
// CheckCodePrefix::D407,
// CheckCodePrefix::D408,
// CheckCodePrefix::D409,
// CheckCodePrefix::D410,
// CheckCodePrefix::D411,
CheckCodePrefix::D412,
// CheckCodePrefix::D413,
CheckCodePrefix::D414,
// CheckCodePrefix::D415,
// CheckCodePrefix::D416,
// CheckCodePrefix::D417,
CheckCodePrefix::D418,
CheckCodePrefix::D419,
], ],
DocstringConvention::NumPy => vec![ DocstringConvention::Numpy => vec![
// All errors except D107, D203, D212, D213, D402, D413, D415, D416, and D417. // Covered by the `convention` setting.
CheckCodePrefix::D100,
CheckCodePrefix::D101,
CheckCodePrefix::D102,
CheckCodePrefix::D103,
CheckCodePrefix::D104,
CheckCodePrefix::D105,
CheckCodePrefix::D106,
// CheckCodePrefix::D107,
CheckCodePrefix::D200,
CheckCodePrefix::D201,
CheckCodePrefix::D202,
// CheckCodePrefix::D203,
CheckCodePrefix::D204,
CheckCodePrefix::D205,
CheckCodePrefix::D206,
CheckCodePrefix::D207,
CheckCodePrefix::D208,
CheckCodePrefix::D209,
CheckCodePrefix::D210,
CheckCodePrefix::D211,
// CheckCodePrefix::D212,
// CheckCodePrefix::D213,
CheckCodePrefix::D214,
CheckCodePrefix::D215,
CheckCodePrefix::D300,
CheckCodePrefix::D301,
CheckCodePrefix::D400,
// CheckCodePrefix::D402,
CheckCodePrefix::D403,
CheckCodePrefix::D404,
CheckCodePrefix::D405,
CheckCodePrefix::D406,
CheckCodePrefix::D407,
CheckCodePrefix::D408,
CheckCodePrefix::D409,
CheckCodePrefix::D410,
CheckCodePrefix::D411,
CheckCodePrefix::D412,
// CheckCodePrefix::D413,
CheckCodePrefix::D414,
// CheckCodePrefix::D415,
// CheckCodePrefix::D416,
// CheckCodePrefix::D417,
CheckCodePrefix::D418,
CheckCodePrefix::D419,
], ],
DocstringConvention::Google => vec![ DocstringConvention::Google => vec![
// All errors except D203, D204, D213, D215, D400, D401, D404, D406, D407, D408, // Covered by the `convention` setting.
// D409 and D413.
CheckCodePrefix::D100,
CheckCodePrefix::D101,
CheckCodePrefix::D102,
CheckCodePrefix::D103,
CheckCodePrefix::D104,
CheckCodePrefix::D105,
CheckCodePrefix::D106,
CheckCodePrefix::D107,
CheckCodePrefix::D200,
CheckCodePrefix::D201,
CheckCodePrefix::D202,
// CheckCodePrefix::D203,
// CheckCodePrefix::D204,
CheckCodePrefix::D205,
CheckCodePrefix::D206,
CheckCodePrefix::D207,
CheckCodePrefix::D208,
CheckCodePrefix::D209,
CheckCodePrefix::D210,
CheckCodePrefix::D211,
CheckCodePrefix::D212,
// CheckCodePrefix::D213,
CheckCodePrefix::D214,
// CheckCodePrefix::D215,
CheckCodePrefix::D300,
CheckCodePrefix::D301,
// CheckCodePrefix::D400,
CheckCodePrefix::D402,
CheckCodePrefix::D403,
// CheckCodePrefix::D404,
CheckCodePrefix::D405,
// CheckCodePrefix::D406,
// CheckCodePrefix::D407,
// CheckCodePrefix::D408,
// CheckCodePrefix::D409,
CheckCodePrefix::D410,
CheckCodePrefix::D411,
CheckCodePrefix::D412,
// CheckCodePrefix::D413,
CheckCodePrefix::D414,
CheckCodePrefix::D415,
CheckCodePrefix::D416,
CheckCodePrefix::D417,
CheckCodePrefix::D418,
CheckCodePrefix::D419,
], ],
} }
} }
@ -509,7 +372,7 @@ pub fn resolve_select(
plugins: &[Plugin], plugins: &[Plugin],
) -> BTreeSet<CheckCodePrefix> { ) -> BTreeSet<CheckCodePrefix> {
// Include default Pyflakes and pycodestyle checks. // Include default Pyflakes and pycodestyle checks.
let mut select = BTreeSet::from([CheckCodePrefix::E, CheckCodePrefix::F, CheckCodePrefix::W]); let mut select = BTreeSet::from([CheckCodePrefix::F, CheckCodePrefix::E, CheckCodePrefix::W]);
// Add prefix codes for every plugin. // Add prefix codes for every plugin.
for plugin in plugins { for plugin in plugins {

View File

@ -36,9 +36,3 @@ urls = { repository = "https://github.com/charliermarsh/ruff-lsp" }
[tool.maturin] [tool.maturin]
bindings = "bin" bindings = "bin"
strip = true strip = true
[tool.ruff]
line-length = 88
[tool.ruff.pydocstyle]
convention = "google"

View File

@ -998,6 +998,13 @@
"enum": [ "enum": [
"numpy" "numpy"
] ]
},
{
"description": "Use PEP257-style docstrings.",
"type": "string",
"enum": [
"pep257"
]
} }
] ]
}, },
@ -1415,7 +1422,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"convention": { "convention": {
"description": "Whether to use Google-style or Numpy-style conventions when detecting docstring sections. By default, conventions will be inferred from the available sections.", "description": "Whether to use Google-style or NumPy-style conventions or the PEP257 defaults when analyzing docstring sections.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Convention" "$ref": "#/definitions/Convention"

View File

@ -924,7 +924,7 @@ pub fn sections(checker: &mut Checker, docstring: &Docstring, convention: Option
numpy_section(checker, docstring, context); numpy_section(checker, docstring, context);
} }
} }
None => { Some(Convention::Pep257) | None => {
// First, interpret as NumPy-style sections. // First, interpret as NumPy-style sections.
let mut found_numpy_section = false; let mut found_numpy_section = false;
for context in &section_contexts(&lines, &SectionStyle::Numpy) { for context in &section_contexts(&lines, &SectionStyle::Numpy) {

View File

@ -4,6 +4,8 @@ use ruff_macros::ConfigurationOptions;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::registry::CheckCode;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")] #[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub enum Convention { pub enum Convention {
@ -11,6 +13,161 @@ pub enum Convention {
Google, Google,
/// Use NumPy-style docstrings. /// Use NumPy-style docstrings.
Numpy, Numpy,
/// Use PEP257-style docstrings.
Pep257,
}
impl Convention {
pub fn codes(&self) -> Vec<CheckCode> {
match self {
Convention::Google => vec![
// All errors except D203, D204, D213, D215, D400, D401, D404, D406, D407, D408,
// D409 and D413.
CheckCode::D100,
CheckCode::D101,
CheckCode::D102,
CheckCode::D103,
CheckCode::D104,
CheckCode::D105,
CheckCode::D106,
CheckCode::D107,
CheckCode::D200,
CheckCode::D201,
CheckCode::D202,
// CheckCode::D203,
// CheckCode::D204,
CheckCode::D205,
CheckCode::D206,
CheckCode::D207,
CheckCode::D208,
CheckCode::D209,
CheckCode::D210,
CheckCode::D211,
CheckCode::D212,
// CheckCode::D213,
CheckCode::D214,
// CheckCode::D215,
CheckCode::D300,
CheckCode::D301,
// CheckCode::D400,
CheckCode::D402,
CheckCode::D403,
// CheckCode::D404,
CheckCode::D405,
// CheckCode::D406,
// CheckCode::D407,
// CheckCode::D408,
// CheckCode::D409,
CheckCode::D410,
CheckCode::D411,
CheckCode::D412,
// CheckCode::D413,
CheckCode::D414,
CheckCode::D415,
CheckCode::D416,
CheckCode::D417,
CheckCode::D418,
CheckCode::D419,
],
Convention::Numpy => vec![
// All errors except D107, D203, D212, D213, D402, D413, D415, D416, and D417.
CheckCode::D100,
CheckCode::D101,
CheckCode::D102,
CheckCode::D103,
CheckCode::D104,
CheckCode::D105,
CheckCode::D106,
// CheckCode::D107,
CheckCode::D200,
CheckCode::D201,
CheckCode::D202,
// CheckCode::D203,
CheckCode::D204,
CheckCode::D205,
CheckCode::D206,
CheckCode::D207,
CheckCode::D208,
CheckCode::D209,
CheckCode::D210,
CheckCode::D211,
// CheckCode::D212,
// CheckCode::D213,
CheckCode::D214,
CheckCode::D215,
CheckCode::D300,
CheckCode::D301,
CheckCode::D400,
// CheckCode::D402,
CheckCode::D403,
CheckCode::D404,
CheckCode::D405,
CheckCode::D406,
CheckCode::D407,
CheckCode::D408,
CheckCode::D409,
CheckCode::D410,
CheckCode::D411,
CheckCode::D412,
// CheckCode::D413,
CheckCode::D414,
// CheckCode::D415,
// CheckCode::D416,
// CheckCode::D417,
CheckCode::D418,
CheckCode::D419,
],
Convention::Pep257 => vec![
// All errors except D203, D212, D213, D214, D215, D404, D405, D406, D407, D408,
// D409, D410, D411, D413, D415, D416 and D417.
CheckCode::D100,
CheckCode::D101,
CheckCode::D102,
CheckCode::D103,
CheckCode::D104,
CheckCode::D105,
CheckCode::D106,
CheckCode::D107,
CheckCode::D200,
CheckCode::D201,
CheckCode::D202,
// CheckCode::D203,
CheckCode::D204,
CheckCode::D205,
CheckCode::D206,
CheckCode::D207,
CheckCode::D208,
CheckCode::D209,
CheckCode::D210,
CheckCode::D211,
// CheckCode::D212,
// CheckCode::D213,
// CheckCode::D214,
// CheckCode::D215,
CheckCode::D300,
CheckCode::D301,
CheckCode::D400,
CheckCode::D402,
CheckCode::D403,
// CheckCode::D404,
// CheckCode::D405,
// CheckCode::D406,
// CheckCode::D407,
// CheckCode::D408,
// CheckCode::D409,
// CheckCode::D410,
// CheckCode::D411,
CheckCode::D412,
// CheckCode::D413,
CheckCode::D414,
// CheckCode::D415,
// CheckCode::D416,
// CheckCode::D417,
CheckCode::D418,
CheckCode::D419,
],
}
}
} }
#[derive( #[derive(
@ -26,9 +183,8 @@ pub struct Options {
convention = "google" convention = "google"
"# "#
)] )]
/// Whether to use Google-style or Numpy-style conventions when detecting /// Whether to use Google-style or NumPy-style conventions or the PEP257
/// docstring sections. By default, conventions will be inferred from /// defaults when analyzing docstring sections.
/// the available sections.
pub convention: Option<Convention>, pub convention: Option<Convention>,
} }

View File

@ -114,6 +114,12 @@ impl Settings {
.dummy_variable_rgx .dummy_variable_rgx
.unwrap_or_else(|| DEFAULT_DUMMY_VARIABLE_RGX.clone()), .unwrap_or_else(|| DEFAULT_DUMMY_VARIABLE_RGX.clone()),
enabled: resolve_codes( enabled: resolve_codes(
config
.pydocstyle
.as_ref()
.and_then(|pydocstyle| pydocstyle.convention)
.map(|convention| convention.codes())
.unwrap_or_default(),
[CheckCodeSpec { [CheckCodeSpec {
select: &config select: &config
.select .select
@ -135,6 +141,7 @@ impl Settings {
fix: config.fix.unwrap_or(false), fix: config.fix.unwrap_or(false),
fix_only: config.fix_only.unwrap_or(false), fix_only: config.fix_only.unwrap_or(false),
fixable: resolve_codes( fixable: resolve_codes(
vec![],
[CheckCodeSpec { [CheckCodeSpec {
select: &config.fixable.unwrap_or_else(|| CATEGORIES.to_vec()), select: &config.fixable.unwrap_or_else(|| CATEGORIES.to_vec()),
ignore: &config.unfixable.unwrap_or_default(), ignore: &config.unfixable.unwrap_or_default(),
@ -384,8 +391,11 @@ struct CheckCodeSpec<'a> {
/// Given a set of selected and ignored prefixes, resolve the set of enabled /// Given a set of selected and ignored prefixes, resolve the set of enabled
/// error codes. /// error codes.
fn resolve_codes<'a>(specs: impl Iterator<Item = CheckCodeSpec<'a>>) -> FxHashSet<CheckCode> { fn resolve_codes<'a>(
let mut codes: FxHashSet<CheckCode> = FxHashSet::default(); baseline: Vec<CheckCode>,
specs: impl Iterator<Item = CheckCodeSpec<'a>>,
) -> FxHashSet<CheckCode> {
let mut codes: FxHashSet<CheckCode> = FxHashSet::from_iter(baseline);
for spec in specs { for spec in specs {
for specificity in [ for specificity in [
SuffixLength::None, SuffixLength::None,
@ -423,6 +433,7 @@ mod tests {
#[test] #[test]
fn check_codes() { fn check_codes() {
let actual = resolve_codes( let actual = resolve_codes(
vec![],
[CheckCodeSpec { [CheckCodeSpec {
select: &[CheckCodePrefix::W], select: &[CheckCodePrefix::W],
ignore: &[], ignore: &[],
@ -433,6 +444,7 @@ mod tests {
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes( let actual = resolve_codes(
vec![],
[CheckCodeSpec { [CheckCodeSpec {
select: &[CheckCodePrefix::W6], select: &[CheckCodePrefix::W6],
ignore: &[], ignore: &[],
@ -443,6 +455,7 @@ mod tests {
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes( let actual = resolve_codes(
vec![],
[CheckCodeSpec { [CheckCodeSpec {
select: &[CheckCodePrefix::W], select: &[CheckCodePrefix::W],
ignore: &[CheckCodePrefix::W292], ignore: &[CheckCodePrefix::W292],
@ -453,6 +466,7 @@ mod tests {
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes( let actual = resolve_codes(
vec![],
[CheckCodeSpec { [CheckCodeSpec {
select: &[CheckCodePrefix::W605], select: &[CheckCodePrefix::W605],
ignore: &[CheckCodePrefix::W605], ignore: &[CheckCodePrefix::W605],
@ -463,6 +477,7 @@ mod tests {
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes( let actual = resolve_codes(
vec![],
[ [
CheckCodeSpec { CheckCodeSpec {
select: &[CheckCodePrefix::W], select: &[CheckCodePrefix::W],
@ -479,6 +494,7 @@ mod tests {
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes( let actual = resolve_codes(
vec![],
[ [
CheckCodeSpec { CheckCodeSpec {
select: &[CheckCodePrefix::W], select: &[CheckCodePrefix::W],