mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
Represent per-file ignores as a map (#531)
This commit is contained in:
parent
5aa8455258
commit
5797884262
11 changed files with 166 additions and 133 deletions
|
@ -42,7 +42,10 @@ pub fn convert(config: HashMap<String, HashMap<String, Option<String>>>) -> Resu
|
||||||
}
|
}
|
||||||
"per-file-ignores" | "per_file_ignores" => {
|
"per-file-ignores" | "per_file_ignores" => {
|
||||||
match parser::parse_files_to_codes_mapping(value.as_ref()) {
|
match parser::parse_files_to_codes_mapping(value.as_ref()) {
|
||||||
Ok(per_file_ignores) => options.per_file_ignores = Some(per_file_ignores),
|
Ok(per_file_ignores) => {
|
||||||
|
options.per_file_ignores =
|
||||||
|
Some(parser::collect_per_file_ignores(per_file_ignores))
|
||||||
|
}
|
||||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -5,7 +6,7 @@ use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use ruff::checks_gen::CheckCodePrefix;
|
use ruff::checks_gen::CheckCodePrefix;
|
||||||
use ruff::settings::types::StrCheckCodePair;
|
use ruff::settings::types::PatternPrefixPair;
|
||||||
|
|
||||||
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||||
|
|
||||||
|
@ -70,15 +71,15 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the list of `StrCheckCodePair` pairs for the current state.
|
/// Generate the list of `StrCheckCodePair` pairs for the current state.
|
||||||
fn parse(&self) -> Vec<StrCheckCodePair> {
|
fn parse(&self) -> Vec<PatternPrefixPair> {
|
||||||
let mut codes: Vec<StrCheckCodePair> = vec![];
|
let mut codes: Vec<PatternPrefixPair> = vec![];
|
||||||
for code in &self.codes {
|
for code in &self.codes {
|
||||||
match CheckCodePrefix::from_str(code) {
|
match CheckCodePrefix::from_str(code) {
|
||||||
Ok(code) => {
|
Ok(code) => {
|
||||||
for filename in &self.filenames {
|
for filename in &self.filenames {
|
||||||
codes.push(StrCheckCodePair {
|
codes.push(PatternPrefixPair {
|
||||||
pattern: filename.clone(),
|
pattern: filename.clone(),
|
||||||
code: code.clone(),
|
prefix: code.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,11 +128,11 @@ fn tokenize_files_to_codes_mapping(value: &str) -> Vec<Token> {
|
||||||
/// Parse a 'files-to-codes' mapping, mimicking Flake8's internal logic.
|
/// Parse a 'files-to-codes' mapping, mimicking Flake8's internal logic.
|
||||||
///
|
///
|
||||||
/// See: https://github.com/PyCQA/flake8/blob/7dfe99616fc2f07c0017df2ba5fa884158f3ea8a/src/flake8/utils.py#L45
|
/// See: https://github.com/PyCQA/flake8/blob/7dfe99616fc2f07c0017df2ba5fa884158f3ea8a/src/flake8/utils.py#L45
|
||||||
pub fn parse_files_to_codes_mapping(value: &str) -> Result<Vec<StrCheckCodePair>> {
|
pub fn parse_files_to_codes_mapping(value: &str) -> Result<Vec<PatternPrefixPair>> {
|
||||||
if value.trim().is_empty() {
|
if value.trim().is_empty() {
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
let mut codes: Vec<StrCheckCodePair> = vec![];
|
let mut codes: Vec<PatternPrefixPair> = vec![];
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
for token in tokenize_files_to_codes_mapping(value) {
|
for token in tokenize_files_to_codes_mapping(value) {
|
||||||
if matches!(token.token_name, TokenType::Comma | TokenType::Ws) {
|
if matches!(token.token_name, TokenType::Comma | TokenType::Ws) {
|
||||||
|
@ -166,12 +167,26 @@ pub fn parse_files_to_codes_mapping(value: &str) -> Result<Vec<StrCheckCodePair>
|
||||||
Ok(codes)
|
Ok(codes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect a list of `PatternPrefixPair` structs as a `BTreeMap`.
|
||||||
|
pub fn collect_per_file_ignores(
|
||||||
|
pairs: Vec<PatternPrefixPair>,
|
||||||
|
) -> BTreeMap<String, Vec<CheckCodePrefix>> {
|
||||||
|
let mut per_file_ignores: BTreeMap<String, Vec<CheckCodePrefix>> = BTreeMap::new();
|
||||||
|
for pair in pairs {
|
||||||
|
per_file_ignores
|
||||||
|
.entry(pair.pattern)
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(pair.prefix);
|
||||||
|
}
|
||||||
|
per_file_ignores
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use ruff::checks_gen::CheckCodePrefix;
|
use ruff::checks_gen::CheckCodePrefix;
|
||||||
use ruff::settings::types::StrCheckCodePair;
|
use ruff::settings::types::PatternPrefixPair;
|
||||||
|
|
||||||
use crate::parser::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
use crate::parser::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||||
|
|
||||||
|
@ -232,11 +247,11 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn it_parse_files_to_codes_mapping() -> Result<()> {
|
fn it_parse_files_to_codes_mapping() -> Result<()> {
|
||||||
let actual = parse_files_to_codes_mapping("")?;
|
let actual = parse_files_to_codes_mapping("")?;
|
||||||
let expected: Vec<StrCheckCodePair> = vec![];
|
let expected: Vec<PatternPrefixPair> = vec![];
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
|
||||||
let actual = parse_files_to_codes_mapping(" ")?;
|
let actual = parse_files_to_codes_mapping(" ")?;
|
||||||
let expected: Vec<StrCheckCodePair> = vec![];
|
let expected: Vec<PatternPrefixPair> = vec![];
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
|
||||||
// Ex) locust
|
// Ex) locust
|
||||||
|
@ -248,14 +263,14 @@ mod tests {
|
||||||
.strip_prefix("per-file-ignores =")
|
.strip_prefix("per-file-ignores =")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)?;
|
)?;
|
||||||
let expected: Vec<StrCheckCodePair> = vec![
|
let expected: Vec<PatternPrefixPair> = vec![
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "locust/test/*".to_string(),
|
pattern: "locust/test/*".to_string(),
|
||||||
code: CheckCodePrefix::F841,
|
prefix: CheckCodePrefix::F841,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "examples/*".to_string(),
|
pattern: "examples/*".to_string(),
|
||||||
code: CheckCodePrefix::F841,
|
prefix: CheckCodePrefix::F841,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
@ -268,26 +283,26 @@ mod tests {
|
||||||
.strip_prefix("per-file-ignores =")
|
.strip_prefix("per-file-ignores =")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)?;
|
)?;
|
||||||
let expected: Vec<StrCheckCodePair> = vec![
|
let expected: Vec<PatternPrefixPair> = vec![
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "t/*".to_string(),
|
pattern: "t/*".to_string(),
|
||||||
code: CheckCodePrefix::D,
|
prefix: CheckCodePrefix::D,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "setup.py".to_string(),
|
pattern: "setup.py".to_string(),
|
||||||
code: CheckCodePrefix::D,
|
prefix: CheckCodePrefix::D,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "examples/*".to_string(),
|
pattern: "examples/*".to_string(),
|
||||||
code: CheckCodePrefix::D,
|
prefix: CheckCodePrefix::D,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "docs/*".to_string(),
|
pattern: "docs/*".to_string(),
|
||||||
code: CheckCodePrefix::D,
|
prefix: CheckCodePrefix::D,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "extra/*".to_string(),
|
pattern: "extra/*".to_string(),
|
||||||
code: CheckCodePrefix::D,
|
prefix: CheckCodePrefix::D,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
@ -306,50 +321,50 @@ mod tests {
|
||||||
.strip_prefix("per-file-ignores =")
|
.strip_prefix("per-file-ignores =")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)?;
|
)?;
|
||||||
let expected: Vec<StrCheckCodePair> = vec![
|
let expected: Vec<PatternPrefixPair> = vec![
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/__init__.py".to_string(),
|
pattern: "scrapy/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::E402,
|
prefix: CheckCodePrefix::E402,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/core/downloader/handlers/http.py".to_string(),
|
pattern: "scrapy/core/downloader/handlers/http.py".to_string(),
|
||||||
code: CheckCodePrefix::F401,
|
prefix: CheckCodePrefix::F401,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/http/__init__.py".to_string(),
|
pattern: "scrapy/http/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::F401,
|
prefix: CheckCodePrefix::F401,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::E402,
|
prefix: CheckCodePrefix::E402,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::F401,
|
prefix: CheckCodePrefix::F401,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/selector/__init__.py".to_string(),
|
pattern: "scrapy/selector/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::F401,
|
prefix: CheckCodePrefix::F401,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/spiders/__init__.py".to_string(),
|
pattern: "scrapy/spiders/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::E402,
|
prefix: CheckCodePrefix::E402,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/spiders/__init__.py".to_string(),
|
pattern: "scrapy/spiders/__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::F401,
|
prefix: CheckCodePrefix::F401,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/utils/url.py".to_string(),
|
pattern: "scrapy/utils/url.py".to_string(),
|
||||||
code: CheckCodePrefix::F403,
|
prefix: CheckCodePrefix::F403,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "scrapy/utils/url.py".to_string(),
|
pattern: "scrapy/utils/url.py".to_string(),
|
||||||
code: CheckCodePrefix::F405,
|
prefix: CheckCodePrefix::F405,
|
||||||
},
|
},
|
||||||
StrCheckCodePair {
|
PatternPrefixPair {
|
||||||
pattern: "tests/test_loader.py".to_string(),
|
pattern: "tests/test_loader.py".to_string(),
|
||||||
code: CheckCodePrefix::E741,
|
prefix: CheckCodePrefix::E741,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
|
4
resources/test/fixtures/pyproject.toml
vendored
4
resources/test/fixtures/pyproject.toml
vendored
|
@ -5,9 +5,7 @@ extend-exclude = [
|
||||||
"migrations",
|
"migrations",
|
||||||
"directory/also_excluded.py",
|
"directory/also_excluded.py",
|
||||||
]
|
]
|
||||||
per-file-ignores = [
|
per-file-ignores = { "__init__.py" = ["F401"] }
|
||||||
"__init__.py:F401",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.ruff.flake8-quotes]
|
[tool.ruff.flake8-quotes]
|
||||||
inline-quotes = "single"
|
inline-quotes = "single"
|
||||||
|
|
19
src/cli.rs
19
src/cli.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -8,8 +9,8 @@ use regex::Regex;
|
||||||
use crate::checks_gen::CheckCodePrefix;
|
use crate::checks_gen::CheckCodePrefix;
|
||||||
use crate::printer::SerializationFormat;
|
use crate::printer::SerializationFormat;
|
||||||
use crate::settings::configuration::Configuration;
|
use crate::settings::configuration::Configuration;
|
||||||
|
use crate::settings::types::PatternPrefixPair;
|
||||||
use crate::settings::types::PythonVersion;
|
use crate::settings::types::PythonVersion;
|
||||||
use crate::settings::types::StrCheckCodePair;
|
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(author, about = "ruff: An extremely fast Python linter.")]
|
#[command(author, about = "ruff: An extremely fast Python linter.")]
|
||||||
|
@ -61,7 +62,7 @@ pub struct Cli {
|
||||||
pub extend_exclude: Vec<String>,
|
pub extend_exclude: Vec<String>,
|
||||||
/// List of mappings from file pattern to code to exclude
|
/// List of mappings from file pattern to code to exclude
|
||||||
#[arg(long, value_delimiter = ',')]
|
#[arg(long, value_delimiter = ',')]
|
||||||
pub per_file_ignores: Vec<StrCheckCodePair>,
|
pub per_file_ignores: Vec<PatternPrefixPair>,
|
||||||
/// Output serialization format for error messages.
|
/// Output serialization format for error messages.
|
||||||
#[arg(long, value_enum, default_value_t=SerializationFormat::Text)]
|
#[arg(long, value_enum, default_value_t=SerializationFormat::Text)]
|
||||||
pub format: SerializationFormat,
|
pub format: SerializationFormat,
|
||||||
|
@ -143,3 +144,17 @@ pub fn warn_on(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect a list of `PatternPrefixPair` structs as a `BTreeMap`.
|
||||||
|
pub fn collect_per_file_ignores(
|
||||||
|
pairs: Vec<PatternPrefixPair>,
|
||||||
|
) -> BTreeMap<String, Vec<CheckCodePrefix>> {
|
||||||
|
let mut per_file_ignores: BTreeMap<String, Vec<CheckCodePrefix>> = BTreeMap::new();
|
||||||
|
for pair in pairs {
|
||||||
|
per_file_ignores
|
||||||
|
.entry(pair.pattern)
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(pair.prefix);
|
||||||
|
}
|
||||||
|
per_file_ignores
|
||||||
|
}
|
||||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
@ -17,7 +18,8 @@ use walkdir::DirEntry;
|
||||||
use ruff::cache;
|
use ruff::cache;
|
||||||
use ruff::checks::CheckCode;
|
use ruff::checks::CheckCode;
|
||||||
use ruff::checks::CheckKind;
|
use ruff::checks::CheckKind;
|
||||||
use ruff::cli::{warn_on, Cli, Warnable};
|
use ruff::checks_gen::CheckCodePrefix;
|
||||||
|
use ruff::cli::{collect_per_file_ignores, warn_on, Cli, Warnable};
|
||||||
use ruff::fs::iter_python_files;
|
use ruff::fs::iter_python_files;
|
||||||
use ruff::linter::add_noqa_to_path;
|
use ruff::linter::add_noqa_to_path;
|
||||||
use ruff::linter::autoformat_path;
|
use ruff::linter::autoformat_path;
|
||||||
|
@ -27,7 +29,7 @@ use ruff::message::Message;
|
||||||
use ruff::printer::{Printer, SerializationFormat};
|
use ruff::printer::{Printer, SerializationFormat};
|
||||||
use ruff::settings::configuration::Configuration;
|
use ruff::settings::configuration::Configuration;
|
||||||
use ruff::settings::pyproject;
|
use ruff::settings::pyproject;
|
||||||
use ruff::settings::types::{FilePattern, PerFileIgnore};
|
use ruff::settings::types::FilePattern;
|
||||||
use ruff::settings::user::UserConfiguration;
|
use ruff::settings::user::UserConfiguration;
|
||||||
use ruff::settings::Settings;
|
use ruff::settings::Settings;
|
||||||
use ruff::tell_user;
|
use ruff::tell_user;
|
||||||
|
@ -255,11 +257,8 @@ fn inner_main() -> Result<ExitCode> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| FilePattern::from_user(path, &project_root))
|
.map(|path| FilePattern::from_user(path, &project_root))
|
||||||
.collect();
|
.collect();
|
||||||
let per_file_ignores: Vec<PerFileIgnore> = cli
|
let per_file_ignores: BTreeMap<String, Vec<CheckCodePrefix>> =
|
||||||
.per_file_ignores
|
collect_per_file_ignores(cli.per_file_ignores);
|
||||||
.into_iter()
|
|
||||||
.map(|pair| PerFileIgnore::new(pair, &project_root))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut configuration = Configuration::from_pyproject(&pyproject, &project_root)?;
|
let mut configuration = Configuration::from_pyproject(&pyproject, &project_root)?;
|
||||||
if !exclude.is_empty() {
|
if !exclude.is_empty() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! User-provided program settings, taking into account pyproject.toml and command-line options.
|
//! User-provided program settings, taking into account pyproject.toml and command-line options.
|
||||||
//! Structure mirrors the user-facing representation of the various parameters.
|
//! Structure mirrors the user-facing representation of the various parameters.
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
@ -9,7 +10,7 @@ use regex::Regex;
|
||||||
|
|
||||||
use crate::checks_gen::CheckCodePrefix;
|
use crate::checks_gen::CheckCodePrefix;
|
||||||
use crate::settings::pyproject::load_options;
|
use crate::settings::pyproject::load_options;
|
||||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion};
|
use crate::settings::types::{FilePattern, PythonVersion};
|
||||||
use crate::{flake8_quotes, pep8_naming};
|
use crate::{flake8_quotes, pep8_naming};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -21,7 +22,7 @@ pub struct Configuration {
|
||||||
pub extend_select: Vec<CheckCodePrefix>,
|
pub extend_select: Vec<CheckCodePrefix>,
|
||||||
pub ignore: Vec<CheckCodePrefix>,
|
pub ignore: Vec<CheckCodePrefix>,
|
||||||
pub line_length: usize,
|
pub line_length: usize,
|
||||||
pub per_file_ignores: Vec<PerFileIgnore>,
|
pub per_file_ignores: BTreeMap<String, Vec<CheckCodePrefix>>,
|
||||||
pub select: Vec<CheckCodePrefix>,
|
pub select: Vec<CheckCodePrefix>,
|
||||||
pub target_version: PythonVersion,
|
pub target_version: PythonVersion,
|
||||||
// Plugins
|
// Plugins
|
||||||
|
@ -91,12 +92,7 @@ impl Configuration {
|
||||||
extend_select: options.extend_select.unwrap_or_default(),
|
extend_select: options.extend_select.unwrap_or_default(),
|
||||||
ignore: options.ignore.unwrap_or_default(),
|
ignore: options.ignore.unwrap_or_default(),
|
||||||
line_length: options.line_length.unwrap_or(88),
|
line_length: options.line_length.unwrap_or(88),
|
||||||
per_file_ignores: options
|
per_file_ignores: options.per_file_ignores.unwrap_or_default(),
|
||||||
.per_file_ignores
|
|
||||||
.unwrap_or_default()
|
|
||||||
.into_iter()
|
|
||||||
.map(|pair| PerFileIgnore::new(pair, project_root))
|
|
||||||
.collect(),
|
|
||||||
// Plugins
|
// Plugins
|
||||||
flake8_quotes: options
|
flake8_quotes: options
|
||||||
.flake8_quotes
|
.flake8_quotes
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Effective program settings, taking into account pyproject.toml and command-line options.
|
//! Effective program settings, taking into account pyproject.toml and command-line options.
|
||||||
//! Structure is optimized for internal usage, as opposed to external visibility or parsing.
|
//! Structure is optimized for internal usage, as opposed to external visibility or parsing.
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -47,7 +47,7 @@ impl Settings {
|
||||||
flake8_quotes: config.flake8_quotes,
|
flake8_quotes: config.flake8_quotes,
|
||||||
line_length: config.line_length,
|
line_length: config.line_length,
|
||||||
pep8_naming: config.pep8_naming,
|
pep8_naming: config.pep8_naming,
|
||||||
per_file_ignores: config.per_file_ignores,
|
per_file_ignores: resolve_per_file_ignores(&config.per_file_ignores),
|
||||||
target_version: config.target_version,
|
target_version: config.target_version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,10 +56,10 @@ impl Settings {
|
||||||
Self {
|
Self {
|
||||||
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
||||||
enabled: BTreeSet::from([check_code]),
|
enabled: BTreeSet::from([check_code]),
|
||||||
exclude: vec![],
|
exclude: Default::default(),
|
||||||
extend_exclude: vec![],
|
extend_exclude: Default::default(),
|
||||||
line_length: 88,
|
line_length: 88,
|
||||||
per_file_ignores: vec![],
|
per_file_ignores: Default::default(),
|
||||||
target_version: PythonVersion::Py310,
|
target_version: PythonVersion::Py310,
|
||||||
flake8_quotes: Default::default(),
|
flake8_quotes: Default::default(),
|
||||||
pep8_naming: Default::default(),
|
pep8_naming: Default::default(),
|
||||||
|
@ -70,10 +70,10 @@ impl Settings {
|
||||||
Self {
|
Self {
|
||||||
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
||||||
enabled: BTreeSet::from_iter(check_codes),
|
enabled: BTreeSet::from_iter(check_codes),
|
||||||
exclude: vec![],
|
exclude: Default::default(),
|
||||||
extend_exclude: vec![],
|
extend_exclude: Default::default(),
|
||||||
line_length: 88,
|
line_length: 88,
|
||||||
per_file_ignores: vec![],
|
per_file_ignores: Default::default(),
|
||||||
target_version: PythonVersion::Py310,
|
target_version: PythonVersion::Py310,
|
||||||
flake8_quotes: Default::default(),
|
flake8_quotes: Default::default(),
|
||||||
pep8_naming: Default::default(),
|
pep8_naming: Default::default(),
|
||||||
|
@ -136,6 +136,15 @@ fn resolve_codes(
|
||||||
codes
|
codes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_per_file_ignores(
|
||||||
|
per_file_ignores: &BTreeMap<String, Vec<CheckCodePrefix>>,
|
||||||
|
) -> Vec<PerFileIgnore> {
|
||||||
|
per_file_ignores
|
||||||
|
.iter()
|
||||||
|
.map(|(pattern, prefixes)| PerFileIgnore::new(pattern, prefixes, &None))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
//! Options that the user can provide via pyproject.toml.
|
//! Options that the user can provide via pyproject.toml.
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::checks_gen::CheckCodePrefix;
|
use crate::checks_gen::CheckCodePrefix;
|
||||||
use crate::settings::types::{PythonVersion, StrCheckCodePair};
|
use crate::settings::types::PythonVersion;
|
||||||
use crate::{flake8_quotes, pep8_naming};
|
use crate::{flake8_quotes, pep8_naming};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||||
|
@ -16,7 +18,7 @@ pub struct Options {
|
||||||
pub extend_select: Option<Vec<CheckCodePrefix>>,
|
pub extend_select: Option<Vec<CheckCodePrefix>>,
|
||||||
pub ignore: Option<Vec<CheckCodePrefix>>,
|
pub ignore: Option<Vec<CheckCodePrefix>>,
|
||||||
pub extend_ignore: Option<Vec<CheckCodePrefix>>,
|
pub extend_ignore: Option<Vec<CheckCodePrefix>>,
|
||||||
pub per_file_ignores: Option<Vec<StrCheckCodePair>>,
|
pub per_file_ignores: Option<BTreeMap<String, Vec<CheckCodePrefix>>>,
|
||||||
pub dummy_variable_rgx: Option<String>,
|
pub dummy_variable_rgx: Option<String>,
|
||||||
pub target_version: Option<PythonVersion>,
|
pub target_version: Option<PythonVersion>,
|
||||||
// Plugins
|
// Plugins
|
||||||
|
|
|
@ -96,6 +96,7 @@ pub fn load_options(pyproject: &Option<PathBuf>) -> Result<Options> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -107,7 +108,7 @@ mod tests {
|
||||||
use crate::settings::pyproject::{
|
use crate::settings::pyproject::{
|
||||||
find_project_root, find_pyproject_toml, parse_pyproject_toml, Options, Pyproject, Tools,
|
find_project_root, find_pyproject_toml, parse_pyproject_toml, Options, Pyproject, Tools,
|
||||||
};
|
};
|
||||||
use crate::settings::types::StrCheckCodePair;
|
use crate::settings::types::PatternPrefixPair;
|
||||||
use crate::{flake8_quotes, pep8_naming};
|
use crate::{flake8_quotes, pep8_naming};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -319,10 +320,10 @@ other-attribute = 1
|
||||||
extend_select: None,
|
extend_select: None,
|
||||||
ignore: None,
|
ignore: None,
|
||||||
extend_ignore: None,
|
extend_ignore: None,
|
||||||
per_file_ignores: Some(vec![StrCheckCodePair {
|
per_file_ignores: Some(BTreeMap::from([(
|
||||||
pattern: "__init__.py".to_string(),
|
"__init__.py".to_string(),
|
||||||
code: CheckCodePrefix::F401
|
vec![CheckCodePrefix::F401]
|
||||||
}]),
|
),])),
|
||||||
dummy_variable_rgx: None,
|
dummy_variable_rgx: None,
|
||||||
target_version: None,
|
target_version: None,
|
||||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||||
|
@ -357,21 +358,21 @@ other-attribute = 1
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn str_check_code_pair_strings() {
|
fn str_check_code_pair_strings() {
|
||||||
let result = StrCheckCodePair::from_str("foo:E501");
|
let result = PatternPrefixPair::from_str("foo:E501");
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let result = StrCheckCodePair::from_str("foo: E501");
|
let result = PatternPrefixPair::from_str("foo: E501");
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let result = StrCheckCodePair::from_str("E501:foo");
|
let result = PatternPrefixPair::from_str("E501:foo");
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let result = StrCheckCodePair::from_str("E501");
|
let result = PatternPrefixPair::from_str("E501");
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let result = StrCheckCodePair::from_str("foo");
|
let result = PatternPrefixPair::from_str("foo");
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let result = StrCheckCodePair::from_str("foo:E501:E402");
|
let result = PatternPrefixPair::from_str("foo:E501:E402");
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let result = StrCheckCodePair::from_str("**/bar:E501");
|
let result = PatternPrefixPair::from_str("**/bar:E501");
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let result = StrCheckCodePair::from_str("bar:E502");
|
let result = PatternPrefixPair::from_str("bar:E502");
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use glob::Pattern;
|
use glob::Pattern;
|
||||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
use crate::checks::CheckCode;
|
use crate::checks::CheckCode;
|
||||||
use crate::checks_gen::CheckCodePrefix;
|
use crate::checks_gen::CheckCodePrefix;
|
||||||
|
@ -75,24 +75,28 @@ pub struct PerFileIgnore {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerFileIgnore {
|
impl PerFileIgnore {
|
||||||
pub fn new(user_in: StrCheckCodePair, project_root: &Option<PathBuf>) -> Self {
|
pub fn new(
|
||||||
let pattern = FilePattern::from_user(user_in.pattern.as_str(), project_root);
|
pattern: &str,
|
||||||
let codes = BTreeSet::from_iter(user_in.code.codes());
|
prefixes: &[CheckCodePrefix],
|
||||||
|
project_root: &Option<PathBuf>,
|
||||||
|
) -> Self {
|
||||||
|
let pattern = FilePattern::from_user(pattern, project_root);
|
||||||
|
let codes = BTreeSet::from_iter(prefixes.iter().flat_map(|prefix| prefix.codes()));
|
||||||
Self { pattern, codes }
|
Self { pattern, codes }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct StrCheckCodePair {
|
pub struct PatternPrefixPair {
|
||||||
pub pattern: String,
|
pub pattern: String,
|
||||||
pub code: CheckCodePrefix,
|
pub prefix: CheckCodePrefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StrCheckCodePair {
|
impl PatternPrefixPair {
|
||||||
const EXPECTED_PATTERN: &'static str = "<FilePattern>:<CheckCode> pattern";
|
const EXPECTED_PATTERN: &'static str = "<FilePattern>:<CheckCode> pattern";
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for StrCheckCodePair {
|
impl<'de> Deserialize<'de> for PatternPrefixPair {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
|
@ -107,17 +111,7 @@ impl<'de> Deserialize<'de> for StrCheckCodePair {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for StrCheckCodePair {
|
impl FromStr for PatternPrefixPair {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let as_str = format!("{}:{}", self.pattern, self.code.as_ref());
|
|
||||||
serializer.serialize_str(&as_str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for StrCheckCodePair {
|
|
||||||
type Err = anyhow::Error;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||||
|
@ -128,8 +122,8 @@ impl FromStr for StrCheckCodePair {
|
||||||
}
|
}
|
||||||
(tokens[0].trim(), tokens[1].trim())
|
(tokens[0].trim(), tokens[1].trim())
|
||||||
};
|
};
|
||||||
let code = CheckCodePrefix::from_str(code_string)?;
|
|
||||||
let pattern = pattern_str.into();
|
let pattern = pattern_str.into();
|
||||||
Ok(Self { pattern, code })
|
let prefix = CheckCodePrefix::from_str(code_string)?;
|
||||||
|
Ok(Self { pattern, prefix })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
//! Structs to render user-facing settings.
|
//! Structs to render user-facing settings.
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::checks_gen::CheckCodePrefix;
|
use crate::checks_gen::CheckCodePrefix;
|
||||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion};
|
use crate::settings::types::{FilePattern, PythonVersion};
|
||||||
use crate::{flake8_quotes, pep8_naming, Configuration};
|
use crate::{flake8_quotes, pep8_naming, Configuration};
|
||||||
|
|
||||||
/// Struct to render user-facing exclusion patterns.
|
/// Struct to render user-facing exclusion patterns.
|
||||||
|
@ -41,7 +42,7 @@ pub struct UserConfiguration {
|
||||||
pub extend_select: Vec<CheckCodePrefix>,
|
pub extend_select: Vec<CheckCodePrefix>,
|
||||||
pub ignore: Vec<CheckCodePrefix>,
|
pub ignore: Vec<CheckCodePrefix>,
|
||||||
pub line_length: usize,
|
pub line_length: usize,
|
||||||
pub per_file_ignores: Vec<PerFileIgnore>,
|
pub per_file_ignores: BTreeMap<String, Vec<CheckCodePrefix>>,
|
||||||
pub select: Vec<CheckCodePrefix>,
|
pub select: Vec<CheckCodePrefix>,
|
||||||
pub target_version: PythonVersion,
|
pub target_version: PythonVersion,
|
||||||
// Plugins
|
// Plugins
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue