mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:35 +00:00
Add extend-immutable-calls
setting for B008 (#706)
This commit is contained in:
parent
2493d48725
commit
aa7681f9ad
11 changed files with 135 additions and 11 deletions
|
@ -224,6 +224,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -257,6 +258,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -290,6 +292,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -323,6 +326,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -356,6 +360,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
|
@ -432,6 +437,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -466,6 +472,7 @@ mod tests {
|
|||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
|
|
17
resources/test/fixtures/B008_extended.py
vendored
Normal file
17
resources/test/fixtures/B008_extended.py
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
from typing import List
|
||||
|
||||
import fastapi
|
||||
from fastapi import Query
|
||||
|
||||
|
||||
def this_is_okay_extended(db=fastapi.Depends(get_db)):
|
||||
...
|
||||
|
||||
|
||||
def this_is_okay_extended_second(data: List[str] = fastapi.Query(None)):
|
||||
...
|
||||
|
||||
|
||||
# TODO(charlie): Support `import from`.
|
||||
def this_is_not_okay_relative_import_not_listed(data: List[str] = Query(None)):
|
||||
...
|
3
resources/test/fixtures/pyproject.toml
vendored
3
resources/test/fixtures/pyproject.toml
vendored
|
@ -7,6 +7,9 @@ extend-exclude = [
|
|||
]
|
||||
per-file-ignores = { "__init__.py" = ["F401"] }
|
||||
|
||||
[tool.ruff.flake8-bugbear]
|
||||
extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"]
|
||||
|
||||
[tool.ruff.flake8-quotes]
|
||||
inline-quotes = "single"
|
||||
multiline-quotes = "double"
|
||||
|
|
|
@ -1,2 +1,36 @@
|
|||
mod constants;
|
||||
pub mod plugins;
|
||||
pub mod settings;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::{flake8_bugbear, Settings};
|
||||
|
||||
#[test]
|
||||
fn extend_immutable_calls() -> Result<()> {
|
||||
let snapshot = "extend_immutable_calls".to_string();
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/B008_extended.py"),
|
||||
&Settings {
|
||||
flake8_bugbear: flake8_bugbear::settings::Settings {
|
||||
extend_immutable_calls: vec![
|
||||
"fastapi.Depends".to_string(),
|
||||
"fastapi.Query".to_string(),
|
||||
],
|
||||
},
|
||||
..Settings::for_rules(vec![CheckCode::B008])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,23 +23,27 @@ const IMMUTABLE_FUNCS: [&str; 11] = [
|
|||
"re.compile",
|
||||
];
|
||||
|
||||
fn is_immutable_func(expr: &Expr) -> bool {
|
||||
compose_call_path(expr).map_or_else(|| false, |func| IMMUTABLE_FUNCS.contains(&func.as_str()))
|
||||
fn is_immutable_func(expr: &Expr, extend_immutable_calls: &[String]) -> bool {
|
||||
compose_call_path(expr).map_or_else(
|
||||
|| false,
|
||||
|func| IMMUTABLE_FUNCS.contains(&func.as_str()) || extend_immutable_calls.contains(&func),
|
||||
)
|
||||
}
|
||||
|
||||
struct ArgumentDefaultVisitor {
|
||||
struct ArgumentDefaultVisitor<'a> {
|
||||
checks: Vec<(CheckKind, Range)>,
|
||||
extend_immutable_calls: &'a [String],
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<'b> for ArgumentDefaultVisitor
|
||||
impl<'a, 'b> Visitor<'b> for ArgumentDefaultVisitor<'b>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Call { func, args, .. } => {
|
||||
if !is_mutable_func(func)
|
||||
&& !is_immutable_func(func)
|
||||
&& !is_immutable_func(func, &self.extend_immutable_calls)
|
||||
&& !is_nan_or_infinity(func, args)
|
||||
{
|
||||
self.checks.push((
|
||||
|
@ -83,7 +87,10 @@ fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
|
|||
|
||||
/// B008
|
||||
pub fn function_call_argument_default(checker: &mut Checker, arguments: &Arguments) {
|
||||
let mut visitor = ArgumentDefaultVisitor { checks: vec![] };
|
||||
let mut visitor = ArgumentDefaultVisitor {
|
||||
checks: vec![],
|
||||
extend_immutable_calls: &checker.settings.flake8_bugbear.extend_immutable_calls,
|
||||
};
|
||||
for expr in arguments
|
||||
.defaults
|
||||
.iter()
|
||||
|
|
22
src/flake8_bugbear/settings.rs
Normal file
22
src/flake8_bugbear/settings.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
//! Settings for the `pep8-naming` plugin.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
pub struct Options {
|
||||
pub extend_immutable_calls: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Default)]
|
||||
pub struct Settings {
|
||||
pub extend_immutable_calls: Vec<String>,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn from_options(options: Options) -> Self {
|
||||
Self {
|
||||
extend_immutable_calls: options.extend_immutable_calls.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
source: src/flake8_bugbear/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: FunctionCallArgumentDefault
|
||||
location:
|
||||
row: 15
|
||||
column: 66
|
||||
end_location:
|
||||
row: 15
|
||||
column: 77
|
||||
fix: ~
|
||||
|
|
@ -12,7 +12,7 @@ use regex::Regex;
|
|||
use crate::checks_gen::CheckCodePrefix;
|
||||
use crate::settings::pyproject::load_options;
|
||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion};
|
||||
use crate::{flake8_annotations, flake8_quotes, fs, isort, pep8_naming};
|
||||
use crate::{flake8_annotations, flake8_bugbear, flake8_quotes, fs, isort, pep8_naming};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Configuration {
|
||||
|
@ -30,6 +30,7 @@ pub struct Configuration {
|
|||
pub target_version: PythonVersion,
|
||||
// Plugins
|
||||
pub flake8_annotations: flake8_annotations::settings::Settings,
|
||||
pub flake8_bugbear: flake8_bugbear::settings::Settings,
|
||||
pub flake8_quotes: flake8_quotes::settings::Settings,
|
||||
pub isort: isort::settings::Settings,
|
||||
pub pep8_naming: pep8_naming::settings::Settings,
|
||||
|
@ -133,6 +134,10 @@ impl Configuration {
|
|||
.flake8_annotations
|
||||
.map(flake8_annotations::settings::Settings::from_options)
|
||||
.unwrap_or_default(),
|
||||
flake8_bugbear: options
|
||||
.flake8_bugbear
|
||||
.map(flake8_bugbear::settings::Settings::from_options)
|
||||
.unwrap_or_default(),
|
||||
flake8_quotes: options
|
||||
.flake8_quotes
|
||||
.map(flake8_quotes::settings::Settings::from_options)
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::checks::CheckCode;
|
|||
use crate::checks_gen::{CheckCodePrefix, PrefixSpecificity};
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion};
|
||||
use crate::{flake8_annotations, flake8_quotes, isort, pep8_naming};
|
||||
use crate::{flake8_annotations, flake8_bugbear, flake8_quotes, isort, pep8_naming};
|
||||
|
||||
pub mod configuration;
|
||||
pub mod options;
|
||||
|
@ -33,6 +33,7 @@ pub struct Settings {
|
|||
pub target_version: PythonVersion,
|
||||
// Plugins
|
||||
pub flake8_annotations: flake8_annotations::settings::Settings,
|
||||
pub flake8_bugbear: flake8_bugbear::settings::Settings,
|
||||
pub flake8_quotes: flake8_quotes::settings::Settings,
|
||||
pub isort: isort::settings::Settings,
|
||||
pub pep8_naming: pep8_naming::settings::Settings,
|
||||
|
@ -51,6 +52,7 @@ impl Settings {
|
|||
exclude: config.exclude,
|
||||
extend_exclude: config.extend_exclude,
|
||||
flake8_annotations: config.flake8_annotations,
|
||||
flake8_bugbear: config.flake8_bugbear,
|
||||
flake8_quotes: config.flake8_quotes,
|
||||
isort: config.isort,
|
||||
line_length: config.line_length,
|
||||
|
@ -72,6 +74,7 @@ impl Settings {
|
|||
src: vec![path_dedot::CWD.clone()],
|
||||
target_version: PythonVersion::Py310,
|
||||
flake8_annotations: Default::default(),
|
||||
flake8_bugbear: Default::default(),
|
||||
flake8_quotes: Default::default(),
|
||||
isort: Default::default(),
|
||||
pep8_naming: Default::default(),
|
||||
|
@ -89,6 +92,7 @@ impl Settings {
|
|||
src: vec![path_dedot::CWD.clone()],
|
||||
target_version: PythonVersion::Py310,
|
||||
flake8_annotations: Default::default(),
|
||||
flake8_bugbear: Default::default(),
|
||||
flake8_quotes: Default::default(),
|
||||
isort: Default::default(),
|
||||
pep8_naming: Default::default(),
|
||||
|
|
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::checks_gen::CheckCodePrefix;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::{flake8_annotations, flake8_quotes, isort, pep8_naming};
|
||||
use crate::{flake8_annotations, flake8_bugbear, flake8_quotes, isort, pep8_naming};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
|
@ -25,6 +25,7 @@ pub struct Options {
|
|||
pub target_version: Option<PythonVersion>,
|
||||
// Plugins
|
||||
pub flake8_annotations: Option<flake8_annotations::settings::Options>,
|
||||
pub flake8_bugbear: Option<flake8_bugbear::settings::Options>,
|
||||
pub flake8_quotes: Option<flake8_quotes::settings::Options>,
|
||||
pub isort: Option<isort::settings::Options>,
|
||||
pub pep8_naming: Option<pep8_naming::settings::Options>,
|
||||
|
|
|
@ -109,7 +109,7 @@ mod tests {
|
|||
find_project_root, find_pyproject_toml, parse_pyproject_toml, Options, Pyproject, Tools,
|
||||
};
|
||||
use crate::settings::types::PatternPrefixPair;
|
||||
use crate::{flake8_quotes, pep8_naming};
|
||||
use crate::{flake8_bugbear, flake8_quotes, pep8_naming};
|
||||
|
||||
#[test]
|
||||
fn deserialize() -> Result<()> {
|
||||
|
@ -146,6 +146,7 @@ mod tests {
|
|||
src: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -177,6 +178,7 @@ line-length = 79
|
|||
src: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -208,6 +210,7 @@ exclude = ["foo.py"]
|
|||
src: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -239,6 +242,7 @@ select = ["E501"]
|
|||
src: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -271,6 +275,7 @@ ignore = ["E501"]
|
|||
src: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
|
@ -349,6 +354,12 @@ other-attribute = 1
|
|||
src: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: Some(flake8_bugbear::settings::Options {
|
||||
extend_immutable_calls: Some(vec![
|
||||
"fastapi.Depends".to_string(),
|
||||
"fastapi.Query".to_string(),
|
||||
]),
|
||||
}),
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(Quote::Single),
|
||||
multiline_quotes: Some(Quote::Double),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue