Implement flake8-gettext (#3785)

This commit is contained in:
Leiser Fernández Gallo 2023-03-29 01:32:02 +02:00 committed by GitHub
parent 515e436cfa
commit 224e85c6d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 384 additions and 20 deletions

View file

@ -195,6 +195,15 @@ are:
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
- flake8-gettext, licensed as follows:
"""
BSD Zero Clause License
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
- flake8-implicit-str-concat, licensed as follows:
"""
The MIT License (MIT)

View file

@ -248,6 +248,7 @@ quality tools, including:
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)

View file

@ -0,0 +1 @@
_(f"{'value'}")

View file

@ -0,0 +1 @@
_("{}".format("line"))

View file

@ -0,0 +1 @@
_("%s" % "line")

View file

@ -42,11 +42,12 @@ use crate::registry::{AsRule, Rule};
use crate::rules::{
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger,
flake8_django, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions,
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_raise,
flake8_return, flake8_self, flake8_simplify, flake8_tidy_imports, flake8_type_checking,
flake8_unused_arguments, flake8_use_pathlib, mccabe, numpy, pandas_vet, pep8_naming,
pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, tryceratops,
flake8_django, flake8_errmsg, flake8_gettext, flake8_implicit_str_concat,
flake8_import_conventions, flake8_logging_format, flake8_pie, flake8_print, flake8_pyi,
flake8_pytest_style, flake8_raise, flake8_return, flake8_self, flake8_simplify,
flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, flake8_use_pathlib, mccabe,
numpy, pandas_vet, pep8_naming, pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint,
pyupgrade, ruff, tryceratops,
};
use crate::settings::types::PythonVersion;
use crate::settings::{flags, Settings};
@ -2890,6 +2891,29 @@ where
}
}
// flake8-gettext
if self.settings.rules.any_enabled(&[
Rule::FStringInGetTextFuncCall,
Rule::FormatInGetTextFuncCall,
Rule::PrintfInGetTextFuncCall,
]) && flake8_gettext::rules::is_gettext_func_call(
func,
&self.settings.flake8_gettext.functions_names,
) {
if self.settings.rules.enabled(Rule::FStringInGetTextFuncCall) {
self.diagnostics
.extend(flake8_gettext::rules::f_string_in_gettext_func_call(args));
}
if self.settings.rules.enabled(Rule::FormatInGetTextFuncCall) {
self.diagnostics
.extend(flake8_gettext::rules::format_in_gettext_func_call(args));
}
if self.settings.rules.enabled(Rule::PrintfInGetTextFuncCall) {
self.diagnostics
.extend(flake8_gettext::rules::printf_in_gettext_func_call(args));
}
}
// flake8-simplify
if self
.settings

View file

@ -284,6 +284,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
(Flake8Return, "507") => Rule::SuperfluousElseContinue,
(Flake8Return, "508") => Rule::SuperfluousElseBreak,
// flake8-gettext
(Flake8GetText, "001") => Rule::FStringInGetTextFuncCall,
(Flake8GetText, "002") => Rule::FormatInGetTextFuncCall,
(Flake8GetText, "003") => Rule::PrintfInGetTextFuncCall,
// flake8-implicit-str-concat
(Flake8ImplicitStrConcat, "001") => Rule::SingleLineImplicitStringConcatenation,
(Flake8ImplicitStrConcat, "002") => Rule::MultiLineImplicitStringConcatenation,

View file

@ -628,6 +628,10 @@ ruff_macros::register_rules!(
rules::flake8_raise::rules::UnnecessaryParenOnRaiseException,
// flake8-self
rules::flake8_self::rules::PrivateMemberAccess,
// flake8-gettext
rules::flake8_gettext::rules::FStringInGetTextFuncCall,
rules::flake8_gettext::rules::FormatInGetTextFuncCall,
rules::flake8_gettext::rules::PrintfInGetTextFuncCall,
// numpy
rules::numpy::rules::NumpyDeprecatedTypeAlias,
rules::numpy::rules::NumpyLegacyRandom,
@ -778,6 +782,9 @@ pub enum Linter {
/// [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
#[prefix = "TCH"]
Flake8TypeChecking,
/// [flake8-gettext](https://pypi.org/project/flake8-gettext/)
#[prefix = "INT"]
Flake8GetText,
/// [flake8-unused-arguments](https://pypi.org/project/flake8-unused-arguments/)
#[prefix = "ARG"]
Flake8UnusedArguments,

View file

@ -0,0 +1,29 @@
//! Rules from [flake8-gettext](https://pypi.org/project/flake8-gettext/).
pub(crate) mod rules;
pub mod settings;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use insta::assert_yaml_snapshot;
use test_case::test_case;
use crate::registry::Rule;
use crate::settings;
use crate::test::test_path;
#[test_case(Rule::FStringInGetTextFuncCall,Path::new("INT001.py"); "INT001")]
#[test_case(Rule::FormatInGetTextFuncCall, Path::new("INT002.py"); "INT002")]
#[test_case(Rule::PrintfInGetTextFuncCall, Path::new("INT003.py"); "INT003")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_gettext").join(path).as_path(),
&settings::Settings::for_rule(rule_code),
)?;
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View file

@ -0,0 +1,97 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Operator};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::Range;
#[violation]
pub struct FStringInGetTextFuncCall;
impl Violation for FStringInGetTextFuncCall {
#[derive_message_formats]
fn message(&self) -> String {
format!("f-string is resolved before function call; consider `_(\"string %s\") % arg`")
}
}
#[violation]
pub struct FormatInGetTextFuncCall;
impl Violation for FormatInGetTextFuncCall {
#[derive_message_formats]
fn message(&self) -> String {
format!("`format` method argument is resolved before function call; consider `_(\"string %s\") % arg`")
}
}
#[violation]
pub struct PrintfInGetTextFuncCall;
impl Violation for PrintfInGetTextFuncCall {
#[derive_message_formats]
fn message(&self) -> String {
format!("printf-style format is resolved before function call; consider `_(\"string %s\") % arg`")
}
}
/// Returns true if the [`Expr`] is an internationalization function call.
pub fn is_gettext_func_call(func: &Expr, functions_names: &[String]) -> bool {
if let ExprKind::Name { id, .. } = &func.node {
functions_names.contains(id)
} else {
false
}
}
/// INT001
pub fn f_string_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
if let Some(first) = args.first() {
if matches!(first.node, ExprKind::JoinedStr { .. }) {
return Some(Diagnostic::new(
FStringInGetTextFuncCall {},
Range::from(first),
));
}
}
None
}
/// INT002
pub fn format_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
if let Some(first) = args.first() {
if let ExprKind::Call { func, .. } = &first.node {
if let ExprKind::Attribute { attr, .. } = &func.node {
if attr == "format" {
return Some(Diagnostic::new(
FormatInGetTextFuncCall {},
Range::from(first),
));
}
}
}
}
None
}
/// INT003
pub fn printf_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
if let Some(first) = args.first() {
if let ExprKind::BinOp {
op: Operator::Mod { .. },
left,
..
} = &first.node
{
if let ExprKind::Constant {
value: Constant::Str(_),
..
} = left.node
{
return Some(Diagnostic::new(
PrintfInGetTextFuncCall {},
Range::from(first),
));
}
}
}
None
}

View file

@ -0,0 +1,73 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use ruff_macros::{CacheKey, ConfigurationOptions};
#[derive(
Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema,
)]
#[serde(
deny_unknown_fields,
rename_all = "kebab-case",
rename = "Flake8GetTextOptions"
)]
pub struct Options {
#[option(
default = r#"["_", "gettext", "ngettext"]"#,
value_type = "list[str]",
example = r#"function-names = ["_", "gettext", "ngettext", "ugettetxt"]"#
)]
/// The function names to consider as internationalization calls.
pub function_names: Option<Vec<String>>,
#[option(
default = r#"[]"#,
value_type = "list[str]",
example = r#"extend-function-names = ["ugettetxt"]"#
)]
#[serde(default)]
/// Additional function names to consider as internationalization calls, in addition to those
/// included in `function-names`.
pub extend_function_names: Vec<String>,
}
#[derive(Debug, CacheKey)]
pub struct Settings {
pub functions_names: Vec<String>,
}
fn default_func_names() -> Vec<String> {
["_", "gettext", "ngettext"]
.iter()
.map(std::string::ToString::to_string)
.collect()
}
impl Default for Settings {
fn default() -> Self {
Self {
functions_names: default_func_names(),
}
}
}
impl From<Options> for Settings {
fn from(options: Options) -> Self {
Self {
functions_names: options
.function_names
.unwrap_or_else(default_func_names)
.into_iter()
.chain(options.extend_function_names)
.collect(),
}
}
}
impl From<Settings> for Options {
fn from(settings: Settings) -> Self {
Self {
function_names: Some(settings.functions_names),
extend_function_names: vec![],
}
}
}

View file

@ -0,0 +1,19 @@
---
source: crates/ruff/src/rules/flake8_gettext/mod.rs
expression: diagnostics
---
- kind:
name: FStringInGetTextFuncCall
body: "f-string is resolved before function call; consider `_(\"string %s\") % arg`"
suggestion: ~
fixable: false
location:
row: 1
column: 2
end_location:
row: 1
column: 14
fix:
edits: []
parent: ~

View file

@ -0,0 +1,19 @@
---
source: crates/ruff/src/rules/flake8_gettext/mod.rs
expression: diagnostics
---
- kind:
name: FormatInGetTextFuncCall
body: "`format` method argument is resolved before function call; consider `_(\"string %s\") % arg`"
suggestion: ~
fixable: false
location:
row: 1
column: 2
end_location:
row: 1
column: 21
fix:
edits: []
parent: ~

View file

@ -0,0 +1,19 @@
---
source: crates/ruff/src/rules/flake8_gettext/mod.rs
expression: diagnostics
---
- kind:
name: PrintfInGetTextFuncCall
body: "printf-style format is resolved before function call; consider `_(\"string %s\") % arg`"
suggestion: ~
fixable: false
location:
row: 1
column: 2
end_location:
row: 1
column: 15
fix:
edits: []
parent: ~

View file

@ -14,6 +14,7 @@ pub mod flake8_debugger;
pub mod flake8_django;
pub mod flake8_errmsg;
pub mod flake8_executable;
pub mod flake8_gettext;
pub mod flake8_implicit_str_concat;
pub mod flake8_import_conventions;
pub mod flake8_logging_format;

View file

@ -16,9 +16,10 @@ use crate::fs;
use crate::rule_selector::RuleSelector;
use crate::rules::{
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
flake8_errmsg, flake8_gettext, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pytest_style, flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking,
flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint,
pyupgrade,
};
use crate::settings::options::Options;
use crate::settings::types::{
@ -75,6 +76,7 @@ pub struct Configuration {
pub flake8_pytest_style: Option<flake8_pytest_style::settings::Options>,
pub flake8_quotes: Option<flake8_quotes::settings::Options>,
pub flake8_self: Option<flake8_self::settings::Options>,
pub flake8_gettext: Option<flake8_gettext::settings::Options>,
pub flake8_tidy_imports: Option<flake8_tidy_imports::options::Options>,
pub flake8_type_checking: Option<flake8_type_checking::settings::Options>,
pub flake8_unused_arguments: Option<flake8_unused_arguments::settings::Options>,
@ -184,6 +186,7 @@ impl Configuration {
flake8_builtins: options.flake8_builtins,
flake8_comprehensions: options.flake8_comprehensions,
flake8_errmsg: options.flake8_errmsg,
flake8_gettext: options.flake8_gettext,
flake8_implicit_str_concat: options.flake8_implicit_str_concat,
flake8_import_conventions: options.flake8_import_conventions,
flake8_pytest_style: options.flake8_pytest_style,
@ -248,6 +251,7 @@ impl Configuration {
flake8_builtins: self.flake8_builtins.or(config.flake8_builtins),
flake8_comprehensions: self.flake8_comprehensions.or(config.flake8_comprehensions),
flake8_errmsg: self.flake8_errmsg.or(config.flake8_errmsg),
flake8_gettext: self.flake8_gettext.or(config.flake8_gettext),
flake8_implicit_str_concat: self
.flake8_implicit_str_concat
.or(config.flake8_implicit_str_concat),

View file

@ -11,9 +11,10 @@ use crate::registry::Linter;
use crate::rule_selector::{prefix_to_selector, RuleSelector};
use crate::rules::{
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
flake8_errmsg, flake8_gettext, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pytest_style, flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking,
flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint,
pyupgrade,
};
use crate::settings::types::FilePatternSet;
@ -88,6 +89,7 @@ impl Default for Settings {
flake8_import_conventions: flake8_import_conventions::settings::Settings::default(),
flake8_pytest_style: flake8_pytest_style::settings::Settings::default(),
flake8_quotes: flake8_quotes::settings::Settings::default(),
flake8_gettext: flake8_gettext::settings::Settings::default(),
flake8_self: flake8_self::settings::Settings::default(),
flake8_tidy_imports: flake8_tidy_imports::Settings::default(),
flake8_type_checking: flake8_type_checking::settings::Settings::default(),

View file

@ -17,9 +17,10 @@ use crate::registry::{Rule, RuleNamespace, RuleSet, INCOMPATIBLE_CODES};
use crate::rule_selector::{RuleSelector, Specificity};
use crate::rules::{
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
flake8_errmsg, flake8_gettext, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pytest_style, flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking,
flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint,
pyupgrade,
};
use crate::settings::configuration::Configuration;
use crate::settings::types::{FilePatternSet, PerFileIgnore, PythonVersion, SerializationFormat};
@ -112,6 +113,7 @@ pub struct Settings {
pub flake8_errmsg: flake8_errmsg::settings::Settings,
pub flake8_implicit_str_concat: flake8_implicit_str_concat::settings::Settings,
pub flake8_import_conventions: flake8_import_conventions::settings::Settings,
pub flake8_gettext: flake8_gettext::settings::Settings,
pub flake8_pytest_style: flake8_pytest_style::settings::Settings,
pub flake8_quotes: flake8_quotes::settings::Settings,
pub flake8_self: flake8_self::settings::Settings,
@ -216,6 +218,7 @@ impl Settings {
.flake8_unused_arguments
.map(Into::into)
.unwrap_or_default(),
flake8_gettext: config.flake8_gettext.map(Into::into).unwrap_or_default(),
isort: config.isort.map(Into::into).unwrap_or_default(),
mccabe: config.mccabe.map(Into::into).unwrap_or_default(),
pep8_naming: config.pep8_naming.map(Into::into).unwrap_or_default(),

View file

@ -8,9 +8,10 @@ use serde::{Deserialize, Serialize};
use crate::rule_selector::RuleSelector;
use crate::rules::{
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
flake8_errmsg, flake8_gettext, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pytest_style, flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking,
flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint,
pyupgrade,
};
use crate::settings::types::{PythonVersion, SerializationFormat, Version};
@ -456,6 +457,9 @@ pub struct Options {
/// Options for the `flake8-type-checking` plugin.
pub flake8_type_checking: Option<flake8_type_checking::settings::Options>,
#[option_group]
/// Options for the `flake8-gettext` plugin.
pub flake8_gettext: Option<flake8_gettext::settings::Options>,
#[option_group]
/// Options for the `flake8-implicit-str-concat` plugin.
pub flake8_implicit_str_concat: Option<flake8_implicit_str_concat::settings::Options>,
#[option_group]

View file

@ -10,9 +10,10 @@ use ruff::linter::{check_path, LinterResult};
use ruff::registry::AsRule;
use ruff::rules::{
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
flake8_errmsg, flake8_gettext, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pytest_style, flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking,
flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint,
pyupgrade,
};
use ruff::settings::configuration::Configuration;
use ruff::settings::options::Options;
@ -136,6 +137,7 @@ pub fn defaultSettings() -> Result<JsValue, JsValue> {
flake8_pytest_style: Some(flake8_pytest_style::settings::Settings::default().into()),
flake8_quotes: Some(flake8_quotes::settings::Settings::default().into()),
flake8_self: Some(flake8_self::settings::Settings::default().into()),
flake8_gettext: Some(flake8_gettext::settings::Settings::default().into()),
flake8_implicit_str_concat: Some(
flake8_implicit_str_concat::settings::Settings::default().into(),
),

View file

@ -41,6 +41,7 @@ natively, including:
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
@ -138,6 +139,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)

41
ruff.schema.json generated
View file

@ -176,6 +176,17 @@
}
]
},
"flake8-gettext": {
"description": "Options for the `flake8-gettext` plugin.",
"anyOf": [
{
"$ref": "#/definitions/Flake8GetTextOptions"
},
{
"type": "null"
}
]
},
"flake8-implicit-str-concat": {
"description": "Options for the `flake8-implicit-str-concat` plugin.",
"anyOf": [
@ -694,6 +705,30 @@
},
"additionalProperties": false
},
"Flake8GetTextOptions": {
"type": "object",
"properties": {
"extend-function-names": {
"description": "Additional function names to consider as internationalization calls, in addition to those included in `function-names`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"function-names": {
"description": "The function names to consider as internationalization calls.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"Flake8ImplicitStrConcatOptions": {
"type": "object",
"properties": {
@ -1742,6 +1777,12 @@
"INP0",
"INP00",
"INP001",
"INT",
"INT0",
"INT00",
"INT001",
"INT002",
"INT003",
"ISC",
"ISC0",
"ISC00",