mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 04:19:43 +00:00
[ruff
] re
and regex
calls with unraw string as first argument (RUF039
) (#14446)
This commit is contained in:
parent
f8c20258ae
commit
5f09d4a90a
11 changed files with 832 additions and 0 deletions
55
crates/ruff_linter/resources/test/fixtures/ruff/RUF039.py
vendored
Normal file
55
crates/ruff_linter/resources/test/fixtures/ruff/RUF039.py
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import re
|
||||||
|
import regex
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
re.compile('single free-spacing', flags=re.X)
|
||||||
|
re.findall('si\ngle')
|
||||||
|
re.finditer("dou\ble")
|
||||||
|
re.fullmatch('''t\riple single''')
|
||||||
|
re.match("""\triple double""")
|
||||||
|
re.search('two', 'args')
|
||||||
|
re.split("raw", r'second')
|
||||||
|
re.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
re.subn(b"""ytes are""", f"\u006e")
|
||||||
|
|
||||||
|
regex.compile('single free-spacing', flags=regex.X)
|
||||||
|
regex.findall('si\ngle')
|
||||||
|
regex.finditer("dou\ble")
|
||||||
|
regex.fullmatch('''t\riple single''')
|
||||||
|
regex.match("""\triple double""")
|
||||||
|
regex.search('two', 'args')
|
||||||
|
regex.split("raw", r'second')
|
||||||
|
regex.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
regex.subn(b"""ytes are""", f"\u006e")
|
||||||
|
|
||||||
|
regex.template("""(?m)
|
||||||
|
(?:ulti)?
|
||||||
|
(?=(?<!(?<=(?!l)))
|
||||||
|
l(?i:ne)
|
||||||
|
""", flags = regex.X)
|
||||||
|
|
||||||
|
|
||||||
|
# No errors
|
||||||
|
re.compile(R'uppercase')
|
||||||
|
re.findall(not_literal)
|
||||||
|
re.finditer(0, literal_but_not_string)
|
||||||
|
re.fullmatch() # no first argument
|
||||||
|
re.match('string' f'''concatenation''')
|
||||||
|
re.search(R"raw" r'concatenation')
|
||||||
|
re.split(rf"multiple", f"""lags""")
|
||||||
|
re.sub(FR'ee', '''as in free speech''')
|
||||||
|
re.subn(br"""eak your machine with rm -""", rf"""/""")
|
||||||
|
|
||||||
|
regex.compile(R'uppercase')
|
||||||
|
regex.findall(not_literal)
|
||||||
|
regex.finditer(0, literal_but_not_string)
|
||||||
|
regex.fullmatch() # no first argument
|
||||||
|
regex.match('string' f'''concatenation''')
|
||||||
|
regex.search(R"raw" r'concatenation')
|
||||||
|
regex.split(rf"multiple", f"""lags""")
|
||||||
|
regex.sub(FR'ee', '''as in free speech''')
|
||||||
|
regex.subn(br"""eak your machine with rm -""", rf"""/""")
|
||||||
|
|
||||||
|
regex.splititer(both, non_literal)
|
||||||
|
regex.subf(f, lambda _: r'means', '"format"')
|
||||||
|
regex.subfn(fn, f'''a$1n't''', lambda: "'function'")
|
93
crates/ruff_linter/resources/test/fixtures/ruff/RUF039_concat.py
vendored
Normal file
93
crates/ruff_linter/resources/test/fixtures/ruff/RUF039_concat.py
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
re.compile(
|
||||||
|
'implicit'
|
||||||
|
'concatenation'
|
||||||
|
)
|
||||||
|
re.findall(
|
||||||
|
r'''
|
||||||
|
multiline
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
concatenation
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
re.finditer(
|
||||||
|
f'(?P<{group}>Dynamic'
|
||||||
|
r'\s+group'
|
||||||
|
'name)'
|
||||||
|
)
|
||||||
|
re.fullmatch(
|
||||||
|
u'n'r'''eadable'''
|
||||||
|
f'much?'
|
||||||
|
)
|
||||||
|
re.match(
|
||||||
|
b'reak'
|
||||||
|
br'eak'
|
||||||
|
)
|
||||||
|
re.search(
|
||||||
|
r''u''
|
||||||
|
'''okay?'''
|
||||||
|
)
|
||||||
|
re.split(''U"""w"""U'')
|
||||||
|
re.sub(
|
||||||
|
"I''m o"
|
||||||
|
'utta ideas'
|
||||||
|
)
|
||||||
|
re.subn("()"r' am I'"??")
|
||||||
|
|
||||||
|
|
||||||
|
import regex
|
||||||
|
|
||||||
|
|
||||||
|
regex.compile(
|
||||||
|
'implicit'
|
||||||
|
'concatenation'
|
||||||
|
)
|
||||||
|
regex.findall(
|
||||||
|
r'''
|
||||||
|
multiline
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
concatenation
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
regex.finditer(
|
||||||
|
f'(?P<{group}>Dynamic'
|
||||||
|
r'\s+group'
|
||||||
|
'name)'
|
||||||
|
)
|
||||||
|
regex.fullmatch(
|
||||||
|
u'n'r'''eadable'''
|
||||||
|
f'much?'
|
||||||
|
)
|
||||||
|
regex.match(
|
||||||
|
b'reak'
|
||||||
|
br'eak'
|
||||||
|
)
|
||||||
|
regex.search(
|
||||||
|
r''u''
|
||||||
|
'''okay?'''
|
||||||
|
)
|
||||||
|
regex.split(''U"""w"""U'')
|
||||||
|
regex.sub(
|
||||||
|
"I''m o"
|
||||||
|
'utta ideas'
|
||||||
|
)
|
||||||
|
regex.subn("()"r' am I'"??")
|
||||||
|
|
||||||
|
|
||||||
|
regex.template(
|
||||||
|
r'''kitty says'''
|
||||||
|
r""r''r""r'aw'r""
|
||||||
|
)
|
||||||
|
regex.splititer(
|
||||||
|
r'r+r*r?'
|
||||||
|
)
|
||||||
|
regex.subf(
|
||||||
|
rb"haha"
|
||||||
|
br"ust go"
|
||||||
|
br''br""br''
|
||||||
|
)
|
||||||
|
regex.subfn(br'I\s\nee*d\s[O0o]me\x20\Qoffe\E, ' br'b')
|
|
@ -1058,6 +1058,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||||
if checker.enabled(Rule::MapIntVersionParsing) {
|
if checker.enabled(Rule::MapIntVersionParsing) {
|
||||||
ruff::rules::map_int_version_parsing(checker, call);
|
ruff::rules::map_int_version_parsing(checker, call);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::UnrawRePattern) {
|
||||||
|
ruff::rules::unraw_re_pattern(checker, call);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Dict(dict) => {
|
Expr::Dict(dict) => {
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
|
|
|
@ -972,6 +972,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||||
(Ruff, "036") => (RuleGroup::Preview, rules::ruff::rules::NoneNotAtEndOfUnion),
|
(Ruff, "036") => (RuleGroup::Preview, rules::ruff::rules::NoneNotAtEndOfUnion),
|
||||||
(Ruff, "038") => (RuleGroup::Preview, rules::ruff::rules::RedundantBoolLiteral),
|
(Ruff, "038") => (RuleGroup::Preview, rules::ruff::rules::RedundantBoolLiteral),
|
||||||
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
|
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
|
||||||
|
(Ruff, "039") => (RuleGroup::Preview, rules::ruff::rules::UnrawRePattern),
|
||||||
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
||||||
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
||||||
|
|
||||||
|
|
|
@ -399,6 +399,8 @@ mod tests {
|
||||||
#[test_case(Rule::MutableDataclassDefault, Path::new("RUF008_attrs.py"))]
|
#[test_case(Rule::MutableDataclassDefault, Path::new("RUF008_attrs.py"))]
|
||||||
#[test_case(Rule::MapIntVersionParsing, Path::new("RUF048.py"))]
|
#[test_case(Rule::MapIntVersionParsing, Path::new("RUF048.py"))]
|
||||||
#[test_case(Rule::MapIntVersionParsing, Path::new("RUF048_1.py"))]
|
#[test_case(Rule::MapIntVersionParsing, Path::new("RUF048_1.py"))]
|
||||||
|
#[test_case(Rule::UnrawRePattern, Path::new("RUF039.py"))]
|
||||||
|
#[test_case(Rule::UnrawRePattern, Path::new("RUF039_concat.py"))]
|
||||||
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!(
|
let snapshot = format!(
|
||||||
"preview__{}_{}",
|
"preview__{}_{}",
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub(crate) use static_key_dict_comprehension::*;
|
||||||
pub(crate) use test_rules::*;
|
pub(crate) use test_rules::*;
|
||||||
pub(crate) use unnecessary_iterable_allocation_for_first_element::*;
|
pub(crate) use unnecessary_iterable_allocation_for_first_element::*;
|
||||||
pub(crate) use unnecessary_key_check::*;
|
pub(crate) use unnecessary_key_check::*;
|
||||||
|
pub(crate) use unraw_re_pattern::*;
|
||||||
pub(crate) use unsafe_markup_use::*;
|
pub(crate) use unsafe_markup_use::*;
|
||||||
pub(crate) use unused_async::*;
|
pub(crate) use unused_async::*;
|
||||||
pub(crate) use unused_noqa::*;
|
pub(crate) use unused_noqa::*;
|
||||||
|
@ -74,6 +75,7 @@ mod suppression_comment_visitor;
|
||||||
pub(crate) mod test_rules;
|
pub(crate) mod test_rules;
|
||||||
mod unnecessary_iterable_allocation_for_first_element;
|
mod unnecessary_iterable_allocation_for_first_element;
|
||||||
mod unnecessary_key_check;
|
mod unnecessary_key_check;
|
||||||
|
mod unraw_re_pattern;
|
||||||
mod unsafe_markup_use;
|
mod unsafe_markup_use;
|
||||||
mod unused_async;
|
mod unused_async;
|
||||||
mod unused_noqa;
|
mod unused_noqa;
|
||||||
|
|
177
crates/ruff_linter/src/rules/ruff/rules/unraw_re_pattern.rs
Normal file
177
crates/ruff_linter/src/rules/ruff/rules/unraw_re_pattern.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::{
|
||||||
|
BytesLiteral, Expr, ExprBytesLiteral, ExprCall, ExprStringLiteral, StringLiteral,
|
||||||
|
};
|
||||||
|
use ruff_python_semantic::{Modules, SemanticModel};
|
||||||
|
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
|
/// ## What it does
|
||||||
|
/// Reports the following `re` and `regex` calls when
|
||||||
|
/// their first arguments are not raw strings:
|
||||||
|
///
|
||||||
|
/// - For `regex` and `re`: `compile`, `findall`, `finditer`,
|
||||||
|
/// `fullmatch`, `match`, `search`, `split`, `sub`, `subn`.
|
||||||
|
/// - `regex`-specific: `splititer`, `subf`, `subfn`, `template`.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// Regular expressions should be written
|
||||||
|
/// using raw strings to avoid double escaping.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// re.compile("foo\\bar")
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// re.compile(r"foo\bar")
|
||||||
|
/// ```
|
||||||
|
#[violation]
|
||||||
|
pub struct UnrawRePattern {
|
||||||
|
module: RegexModule,
|
||||||
|
func: String,
|
||||||
|
kind: PatternKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Violation for UnrawRePattern {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let Self { module, func, kind } = &self;
|
||||||
|
let call = format!("`{module}.{func}()`");
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
PatternKind::String => format!("First argument to {call} is not raw string"),
|
||||||
|
PatternKind::Bytes => format!("First argument to {call} is not raw bytes literal"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> Option<String> {
|
||||||
|
match self.kind {
|
||||||
|
PatternKind::String => Some("Replace with raw string".to_string()),
|
||||||
|
PatternKind::Bytes => Some("Replace with raw bytes literal".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
enum RegexModule {
|
||||||
|
Re,
|
||||||
|
Regex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegexModule {
|
||||||
|
fn is_function_taking_pattern(self, name: &str) -> bool {
|
||||||
|
match name {
|
||||||
|
"compile" | "findall" | "finditer" | "fullmatch" | "match" | "search" | "split"
|
||||||
|
| "sub" | "subn" => true,
|
||||||
|
"splititer" | "subf" | "subfn" | "template" => self == Self::Regex,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for RegexModule {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
RegexModule::Re => "re",
|
||||||
|
RegexModule::Regex => "regex",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for RegexModule {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"re" => Ok(Self::Re),
|
||||||
|
"regex" => Ok(Self::Regex),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
enum PatternKind {
|
||||||
|
String,
|
||||||
|
Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RUF039
|
||||||
|
pub(crate) fn unraw_re_pattern(checker: &mut Checker, call: &ExprCall) {
|
||||||
|
let semantic = checker.semantic();
|
||||||
|
|
||||||
|
if !semantic.seen_module(Modules::RE) && !semantic.seen_module(Modules::REGEX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some((module, func)) = regex_module_and_func(semantic, call.func.as_ref()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
match call.arguments.args.as_ref().first() {
|
||||||
|
Some(Expr::StringLiteral(ExprStringLiteral { value, .. })) => {
|
||||||
|
value
|
||||||
|
.iter()
|
||||||
|
.for_each(|part| check_string(checker, part, module, func));
|
||||||
|
}
|
||||||
|
Some(Expr::BytesLiteral(ExprBytesLiteral { value, .. })) => {
|
||||||
|
value
|
||||||
|
.iter()
|
||||||
|
.for_each(|part| check_bytes(checker, part, module, func));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regex_module_and_func<'model>(
|
||||||
|
semantic: &SemanticModel<'model>,
|
||||||
|
expr: &'model Expr,
|
||||||
|
) -> Option<(RegexModule, &'model str)> {
|
||||||
|
let qualified_name = semantic.resolve_qualified_name(expr)?;
|
||||||
|
|
||||||
|
if let [module, func] = qualified_name.segments() {
|
||||||
|
let module = RegexModule::from_str(module).ok()?;
|
||||||
|
|
||||||
|
if !module.is_function_taking_pattern(func) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some((module, func));
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_string(checker: &mut Checker, literal: &StringLiteral, module: RegexModule, func: &str) {
|
||||||
|
if literal.flags.prefix().is_raw() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind = PatternKind::String;
|
||||||
|
let func = func.to_string();
|
||||||
|
let range = literal.range;
|
||||||
|
let diagnostic = Diagnostic::new(UnrawRePattern { module, func, kind }, range);
|
||||||
|
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_bytes(checker: &mut Checker, literal: &BytesLiteral, module: RegexModule, func: &str) {
|
||||||
|
if literal.flags.prefix().is_raw() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind = PatternKind::Bytes;
|
||||||
|
let func = func.to_string();
|
||||||
|
let range = literal.range;
|
||||||
|
let diagnostic = Diagnostic::new(UnrawRePattern { module, func, kind }, range);
|
||||||
|
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
|
@ -0,0 +1,211 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
RUF039.py:5:12: RUF039 First argument to `re.compile()` is not raw string
|
||||||
|
|
|
||||||
|
4 | # Errors
|
||||||
|
5 | re.compile('single free-spacing', flags=re.X)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ RUF039
|
||||||
|
6 | re.findall('si\ngle')
|
||||||
|
7 | re.finditer("dou\ble")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:6:12: RUF039 First argument to `re.findall()` is not raw string
|
||||||
|
|
|
||||||
|
4 | # Errors
|
||||||
|
5 | re.compile('single free-spacing', flags=re.X)
|
||||||
|
6 | re.findall('si\ngle')
|
||||||
|
| ^^^^^^^^^ RUF039
|
||||||
|
7 | re.finditer("dou\ble")
|
||||||
|
8 | re.fullmatch('''t\riple single''')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:7:13: RUF039 First argument to `re.finditer()` is not raw string
|
||||||
|
|
|
||||||
|
5 | re.compile('single free-spacing', flags=re.X)
|
||||||
|
6 | re.findall('si\ngle')
|
||||||
|
7 | re.finditer("dou\ble")
|
||||||
|
| ^^^^^^^^^ RUF039
|
||||||
|
8 | re.fullmatch('''t\riple single''')
|
||||||
|
9 | re.match("""\triple double""")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:8:14: RUF039 First argument to `re.fullmatch()` is not raw string
|
||||||
|
|
|
||||||
|
6 | re.findall('si\ngle')
|
||||||
|
7 | re.finditer("dou\ble")
|
||||||
|
8 | re.fullmatch('''t\riple single''')
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ RUF039
|
||||||
|
9 | re.match("""\triple double""")
|
||||||
|
10 | re.search('two', 'args')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:9:10: RUF039 First argument to `re.match()` is not raw string
|
||||||
|
|
|
||||||
|
7 | re.finditer("dou\ble")
|
||||||
|
8 | re.fullmatch('''t\riple single''')
|
||||||
|
9 | re.match("""\triple double""")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ RUF039
|
||||||
|
10 | re.search('two', 'args')
|
||||||
|
11 | re.split("raw", r'second')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:10:11: RUF039 First argument to `re.search()` is not raw string
|
||||||
|
|
|
||||||
|
8 | re.fullmatch('''t\riple single''')
|
||||||
|
9 | re.match("""\triple double""")
|
||||||
|
10 | re.search('two', 'args')
|
||||||
|
| ^^^^^ RUF039
|
||||||
|
11 | re.split("raw", r'second')
|
||||||
|
12 | re.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:11:10: RUF039 First argument to `re.split()` is not raw string
|
||||||
|
|
|
||||||
|
9 | re.match("""\triple double""")
|
||||||
|
10 | re.search('two', 'args')
|
||||||
|
11 | re.split("raw", r'second')
|
||||||
|
| ^^^^^ RUF039
|
||||||
|
12 | re.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
13 | re.subn(b"""ytes are""", f"\u006e")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:12:8: RUF039 First argument to `re.sub()` is not raw string
|
||||||
|
|
|
||||||
|
10 | re.search('two', 'args')
|
||||||
|
11 | re.split("raw", r'second')
|
||||||
|
12 | re.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
| ^^^^^^^^^^^^^ RUF039
|
||||||
|
13 | re.subn(b"""ytes are""", f"\u006e")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:13:9: RUF039 First argument to `re.subn()` is not raw bytes literal
|
||||||
|
|
|
||||||
|
11 | re.split("raw", r'second')
|
||||||
|
12 | re.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
13 | re.subn(b"""ytes are""", f"\u006e")
|
||||||
|
| ^^^^^^^^^^^^^^^ RUF039
|
||||||
|
14 |
|
||||||
|
15 | regex.compile('single free-spacing', flags=regex.X)
|
||||||
|
|
|
||||||
|
= help: Replace with raw bytes literal
|
||||||
|
|
||||||
|
RUF039.py:15:15: RUF039 First argument to `regex.compile()` is not raw string
|
||||||
|
|
|
||||||
|
13 | re.subn(b"""ytes are""", f"\u006e")
|
||||||
|
14 |
|
||||||
|
15 | regex.compile('single free-spacing', flags=regex.X)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ RUF039
|
||||||
|
16 | regex.findall('si\ngle')
|
||||||
|
17 | regex.finditer("dou\ble")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:16:15: RUF039 First argument to `regex.findall()` is not raw string
|
||||||
|
|
|
||||||
|
15 | regex.compile('single free-spacing', flags=regex.X)
|
||||||
|
16 | regex.findall('si\ngle')
|
||||||
|
| ^^^^^^^^^ RUF039
|
||||||
|
17 | regex.finditer("dou\ble")
|
||||||
|
18 | regex.fullmatch('''t\riple single''')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:17:16: RUF039 First argument to `regex.finditer()` is not raw string
|
||||||
|
|
|
||||||
|
15 | regex.compile('single free-spacing', flags=regex.X)
|
||||||
|
16 | regex.findall('si\ngle')
|
||||||
|
17 | regex.finditer("dou\ble")
|
||||||
|
| ^^^^^^^^^ RUF039
|
||||||
|
18 | regex.fullmatch('''t\riple single''')
|
||||||
|
19 | regex.match("""\triple double""")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:18:17: RUF039 First argument to `regex.fullmatch()` is not raw string
|
||||||
|
|
|
||||||
|
16 | regex.findall('si\ngle')
|
||||||
|
17 | regex.finditer("dou\ble")
|
||||||
|
18 | regex.fullmatch('''t\riple single''')
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ RUF039
|
||||||
|
19 | regex.match("""\triple double""")
|
||||||
|
20 | regex.search('two', 'args')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:19:13: RUF039 First argument to `regex.match()` is not raw string
|
||||||
|
|
|
||||||
|
17 | regex.finditer("dou\ble")
|
||||||
|
18 | regex.fullmatch('''t\riple single''')
|
||||||
|
19 | regex.match("""\triple double""")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ RUF039
|
||||||
|
20 | regex.search('two', 'args')
|
||||||
|
21 | regex.split("raw", r'second')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:20:14: RUF039 First argument to `regex.search()` is not raw string
|
||||||
|
|
|
||||||
|
18 | regex.fullmatch('''t\riple single''')
|
||||||
|
19 | regex.match("""\triple double""")
|
||||||
|
20 | regex.search('two', 'args')
|
||||||
|
| ^^^^^ RUF039
|
||||||
|
21 | regex.split("raw", r'second')
|
||||||
|
22 | regex.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:21:13: RUF039 First argument to `regex.split()` is not raw string
|
||||||
|
|
|
||||||
|
19 | regex.match("""\triple double""")
|
||||||
|
20 | regex.search('two', 'args')
|
||||||
|
21 | regex.split("raw", r'second')
|
||||||
|
| ^^^^^ RUF039
|
||||||
|
22 | regex.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
23 | regex.subn(b"""ytes are""", f"\u006e")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:22:11: RUF039 First argument to `regex.sub()` is not raw string
|
||||||
|
|
|
||||||
|
20 | regex.search('two', 'args')
|
||||||
|
21 | regex.split("raw", r'second')
|
||||||
|
22 | regex.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
| ^^^^^^^^^^^^^ RUF039
|
||||||
|
23 | regex.subn(b"""ytes are""", f"\u006e")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039.py:23:12: RUF039 First argument to `regex.subn()` is not raw bytes literal
|
||||||
|
|
|
||||||
|
21 | regex.split("raw", r'second')
|
||||||
|
22 | regex.sub(u'''nicode''', u"f(?i)rst")
|
||||||
|
23 | regex.subn(b"""ytes are""", f"\u006e")
|
||||||
|
| ^^^^^^^^^^^^^^^ RUF039
|
||||||
|
24 |
|
||||||
|
25 | regex.template("""(?m)
|
||||||
|
|
|
||||||
|
= help: Replace with raw bytes literal
|
||||||
|
|
||||||
|
RUF039.py:25:16: RUF039 First argument to `regex.template()` is not raw string
|
||||||
|
|
|
||||||
|
23 | regex.subn(b"""ytes are""", f"\u006e")
|
||||||
|
24 |
|
||||||
|
25 | regex.template("""(?m)
|
||||||
|
| ________________^
|
||||||
|
26 | | (?:ulti)?
|
||||||
|
27 | | (?=(?<!(?<=(?!l)))
|
||||||
|
28 | | l(?i:ne)
|
||||||
|
29 | | """, flags = regex.X)
|
||||||
|
| |___^ RUF039
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
|
@ -0,0 +1,285 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
RUF039_concat.py:5:5: RUF039 First argument to `re.compile()` is not raw string
|
||||||
|
|
|
||||||
|
4 | re.compile(
|
||||||
|
5 | 'implicit'
|
||||||
|
| ^^^^^^^^^^ RUF039
|
||||||
|
6 | 'concatenation'
|
||||||
|
7 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:6:5: RUF039 First argument to `re.compile()` is not raw string
|
||||||
|
|
|
||||||
|
4 | re.compile(
|
||||||
|
5 | 'implicit'
|
||||||
|
6 | 'concatenation'
|
||||||
|
| ^^^^^^^^^^^^^^^ RUF039
|
||||||
|
7 | )
|
||||||
|
8 | re.findall(
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:12:5: RUF039 First argument to `re.findall()` is not raw string
|
||||||
|
|
|
||||||
|
10 | multiline
|
||||||
|
11 | '''
|
||||||
|
12 | """
|
||||||
|
| _____^
|
||||||
|
13 | | concatenation
|
||||||
|
14 | | """
|
||||||
|
| |_______^ RUF039
|
||||||
|
15 | )
|
||||||
|
16 | re.finditer(
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:26:5: RUF039 First argument to `re.match()` is not raw bytes literal
|
||||||
|
|
|
||||||
|
24 | )
|
||||||
|
25 | re.match(
|
||||||
|
26 | b'reak'
|
||||||
|
| ^^^^^^^ RUF039
|
||||||
|
27 | br'eak'
|
||||||
|
28 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw bytes literal
|
||||||
|
|
||||||
|
RUF039_concat.py:30:8: RUF039 First argument to `re.search()` is not raw string
|
||||||
|
|
|
||||||
|
28 | )
|
||||||
|
29 | re.search(
|
||||||
|
30 | r''u''
|
||||||
|
| ^^^ RUF039
|
||||||
|
31 | '''okay?'''
|
||||||
|
32 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:31:5: RUF039 First argument to `re.search()` is not raw string
|
||||||
|
|
|
||||||
|
29 | re.search(
|
||||||
|
30 | r''u''
|
||||||
|
31 | '''okay?'''
|
||||||
|
| ^^^^^^^^^^^ RUF039
|
||||||
|
32 | )
|
||||||
|
33 | re.split(''U"""w"""U'')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:33:10: RUF039 First argument to `re.split()` is not raw string
|
||||||
|
|
|
||||||
|
31 | '''okay?'''
|
||||||
|
32 | )
|
||||||
|
33 | re.split(''U"""w"""U'')
|
||||||
|
| ^^ RUF039
|
||||||
|
34 | re.sub(
|
||||||
|
35 | "I''m o"
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:33:12: RUF039 First argument to `re.split()` is not raw string
|
||||||
|
|
|
||||||
|
31 | '''okay?'''
|
||||||
|
32 | )
|
||||||
|
33 | re.split(''U"""w"""U'')
|
||||||
|
| ^^^^^^^^ RUF039
|
||||||
|
34 | re.sub(
|
||||||
|
35 | "I''m o"
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:33:20: RUF039 First argument to `re.split()` is not raw string
|
||||||
|
|
|
||||||
|
31 | '''okay?'''
|
||||||
|
32 | )
|
||||||
|
33 | re.split(''U"""w"""U'')
|
||||||
|
| ^^^ RUF039
|
||||||
|
34 | re.sub(
|
||||||
|
35 | "I''m o"
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:35:5: RUF039 First argument to `re.sub()` is not raw string
|
||||||
|
|
|
||||||
|
33 | re.split(''U"""w"""U'')
|
||||||
|
34 | re.sub(
|
||||||
|
35 | "I''m o"
|
||||||
|
| ^^^^^^^^ RUF039
|
||||||
|
36 | 'utta ideas'
|
||||||
|
37 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:36:5: RUF039 First argument to `re.sub()` is not raw string
|
||||||
|
|
|
||||||
|
34 | re.sub(
|
||||||
|
35 | "I''m o"
|
||||||
|
36 | 'utta ideas'
|
||||||
|
| ^^^^^^^^^^^^ RUF039
|
||||||
|
37 | )
|
||||||
|
38 | re.subn("()"r' am I'"??")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:38:9: RUF039 First argument to `re.subn()` is not raw string
|
||||||
|
|
|
||||||
|
36 | 'utta ideas'
|
||||||
|
37 | )
|
||||||
|
38 | re.subn("()"r' am I'"??")
|
||||||
|
| ^^^^ RUF039
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:38:21: RUF039 First argument to `re.subn()` is not raw string
|
||||||
|
|
|
||||||
|
36 | 'utta ideas'
|
||||||
|
37 | )
|
||||||
|
38 | re.subn("()"r' am I'"??")
|
||||||
|
| ^^^^ RUF039
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:45:5: RUF039 First argument to `regex.compile()` is not raw string
|
||||||
|
|
|
||||||
|
44 | regex.compile(
|
||||||
|
45 | 'implicit'
|
||||||
|
| ^^^^^^^^^^ RUF039
|
||||||
|
46 | 'concatenation'
|
||||||
|
47 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:46:5: RUF039 First argument to `regex.compile()` is not raw string
|
||||||
|
|
|
||||||
|
44 | regex.compile(
|
||||||
|
45 | 'implicit'
|
||||||
|
46 | 'concatenation'
|
||||||
|
| ^^^^^^^^^^^^^^^ RUF039
|
||||||
|
47 | )
|
||||||
|
48 | regex.findall(
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:52:5: RUF039 First argument to `regex.findall()` is not raw string
|
||||||
|
|
|
||||||
|
50 | multiline
|
||||||
|
51 | '''
|
||||||
|
52 | """
|
||||||
|
| _____^
|
||||||
|
53 | | concatenation
|
||||||
|
54 | | """
|
||||||
|
| |_______^ RUF039
|
||||||
|
55 | )
|
||||||
|
56 | regex.finditer(
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:66:5: RUF039 First argument to `regex.match()` is not raw bytes literal
|
||||||
|
|
|
||||||
|
64 | )
|
||||||
|
65 | regex.match(
|
||||||
|
66 | b'reak'
|
||||||
|
| ^^^^^^^ RUF039
|
||||||
|
67 | br'eak'
|
||||||
|
68 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw bytes literal
|
||||||
|
|
||||||
|
RUF039_concat.py:70:8: RUF039 First argument to `regex.search()` is not raw string
|
||||||
|
|
|
||||||
|
68 | )
|
||||||
|
69 | regex.search(
|
||||||
|
70 | r''u''
|
||||||
|
| ^^^ RUF039
|
||||||
|
71 | '''okay?'''
|
||||||
|
72 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:71:5: RUF039 First argument to `regex.search()` is not raw string
|
||||||
|
|
|
||||||
|
69 | regex.search(
|
||||||
|
70 | r''u''
|
||||||
|
71 | '''okay?'''
|
||||||
|
| ^^^^^^^^^^^ RUF039
|
||||||
|
72 | )
|
||||||
|
73 | regex.split(''U"""w"""U'')
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:73:13: RUF039 First argument to `regex.split()` is not raw string
|
||||||
|
|
|
||||||
|
71 | '''okay?'''
|
||||||
|
72 | )
|
||||||
|
73 | regex.split(''U"""w"""U'')
|
||||||
|
| ^^ RUF039
|
||||||
|
74 | regex.sub(
|
||||||
|
75 | "I''m o"
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:73:15: RUF039 First argument to `regex.split()` is not raw string
|
||||||
|
|
|
||||||
|
71 | '''okay?'''
|
||||||
|
72 | )
|
||||||
|
73 | regex.split(''U"""w"""U'')
|
||||||
|
| ^^^^^^^^ RUF039
|
||||||
|
74 | regex.sub(
|
||||||
|
75 | "I''m o"
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:73:23: RUF039 First argument to `regex.split()` is not raw string
|
||||||
|
|
|
||||||
|
71 | '''okay?'''
|
||||||
|
72 | )
|
||||||
|
73 | regex.split(''U"""w"""U'')
|
||||||
|
| ^^^ RUF039
|
||||||
|
74 | regex.sub(
|
||||||
|
75 | "I''m o"
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:75:5: RUF039 First argument to `regex.sub()` is not raw string
|
||||||
|
|
|
||||||
|
73 | regex.split(''U"""w"""U'')
|
||||||
|
74 | regex.sub(
|
||||||
|
75 | "I''m o"
|
||||||
|
| ^^^^^^^^ RUF039
|
||||||
|
76 | 'utta ideas'
|
||||||
|
77 | )
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:76:5: RUF039 First argument to `regex.sub()` is not raw string
|
||||||
|
|
|
||||||
|
74 | regex.sub(
|
||||||
|
75 | "I''m o"
|
||||||
|
76 | 'utta ideas'
|
||||||
|
| ^^^^^^^^^^^^ RUF039
|
||||||
|
77 | )
|
||||||
|
78 | regex.subn("()"r' am I'"??")
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:78:12: RUF039 First argument to `regex.subn()` is not raw string
|
||||||
|
|
|
||||||
|
76 | 'utta ideas'
|
||||||
|
77 | )
|
||||||
|
78 | regex.subn("()"r' am I'"??")
|
||||||
|
| ^^^^ RUF039
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
||||||
|
|
||||||
|
RUF039_concat.py:78:24: RUF039 First argument to `regex.subn()` is not raw string
|
||||||
|
|
|
||||||
|
76 | 'utta ideas'
|
||||||
|
77 | )
|
||||||
|
78 | regex.subn("()"r' am I'"??")
|
||||||
|
| ^^^^ RUF039
|
||||||
|
|
|
||||||
|
= help: Replace with raw string
|
|
@ -1281,6 +1281,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
"pandas" => self.seen.insert(Modules::PANDAS),
|
"pandas" => self.seen.insert(Modules::PANDAS),
|
||||||
"pytest" => self.seen.insert(Modules::PYTEST),
|
"pytest" => self.seen.insert(Modules::PYTEST),
|
||||||
"re" => self.seen.insert(Modules::RE),
|
"re" => self.seen.insert(Modules::RE),
|
||||||
|
"regex" => self.seen.insert(Modules::REGEX),
|
||||||
"six" => self.seen.insert(Modules::SIX),
|
"six" => self.seen.insert(Modules::SIX),
|
||||||
"subprocess" => self.seen.insert(Modules::SUBPROCESS),
|
"subprocess" => self.seen.insert(Modules::SUBPROCESS),
|
||||||
"tarfile" => self.seen.insert(Modules::TARFILE),
|
"tarfile" => self.seen.insert(Modules::TARFILE),
|
||||||
|
@ -1858,6 +1859,7 @@ bitflags! {
|
||||||
const MARKUPSAFE = 1 << 23;
|
const MARKUPSAFE = 1 << 23;
|
||||||
const FLASK = 1 << 24;
|
const FLASK = 1 << 24;
|
||||||
const ATTRS = 1 << 25;
|
const ATTRS = 1 << 25;
|
||||||
|
const REGEX = 1 << 26;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -3836,6 +3836,7 @@
|
||||||
"RUF035",
|
"RUF035",
|
||||||
"RUF036",
|
"RUF036",
|
||||||
"RUF038",
|
"RUF038",
|
||||||
|
"RUF039",
|
||||||
"RUF04",
|
"RUF04",
|
||||||
"RUF048",
|
"RUF048",
|
||||||
"RUF1",
|
"RUF1",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue