mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:48 +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) {
|
||||
ruff::rules::map_int_version_parsing(checker, call);
|
||||
}
|
||||
if checker.enabled(Rule::UnrawRePattern) {
|
||||
ruff::rules::unraw_re_pattern(checker, call);
|
||||
}
|
||||
}
|
||||
Expr::Dict(dict) => {
|
||||
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, "038") => (RuleGroup::Preview, rules::ruff::rules::RedundantBoolLiteral),
|
||||
(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, "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::MapIntVersionParsing, Path::new("RUF048.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<()> {
|
||||
let snapshot = format!(
|
||||
"preview__{}_{}",
|
||||
|
|
|
@ -31,6 +31,7 @@ pub(crate) use static_key_dict_comprehension::*;
|
|||
pub(crate) use test_rules::*;
|
||||
pub(crate) use unnecessary_iterable_allocation_for_first_element::*;
|
||||
pub(crate) use unnecessary_key_check::*;
|
||||
pub(crate) use unraw_re_pattern::*;
|
||||
pub(crate) use unsafe_markup_use::*;
|
||||
pub(crate) use unused_async::*;
|
||||
pub(crate) use unused_noqa::*;
|
||||
|
@ -74,6 +75,7 @@ mod suppression_comment_visitor;
|
|||
pub(crate) mod test_rules;
|
||||
mod unnecessary_iterable_allocation_for_first_element;
|
||||
mod unnecessary_key_check;
|
||||
mod unraw_re_pattern;
|
||||
mod unsafe_markup_use;
|
||||
mod unused_async;
|
||||
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),
|
||||
"pytest" => self.seen.insert(Modules::PYTEST),
|
||||
"re" => self.seen.insert(Modules::RE),
|
||||
"regex" => self.seen.insert(Modules::REGEX),
|
||||
"six" => self.seen.insert(Modules::SIX),
|
||||
"subprocess" => self.seen.insert(Modules::SUBPROCESS),
|
||||
"tarfile" => self.seen.insert(Modules::TARFILE),
|
||||
|
@ -1858,6 +1859,7 @@ bitflags! {
|
|||
const MARKUPSAFE = 1 << 23;
|
||||
const FLASK = 1 << 24;
|
||||
const ATTRS = 1 << 25;
|
||||
const REGEX = 1 << 26;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -3836,6 +3836,7 @@
|
|||
"RUF035",
|
||||
"RUF036",
|
||||
"RUF038",
|
||||
"RUF039",
|
||||
"RUF04",
|
||||
"RUF048",
|
||||
"RUF1",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue