Skip to content

Commit

Permalink
string_or_bytes_too_long for f-string psarts
Browse files Browse the repository at this point in the history
  • Loading branch information
davidszotten committed Sep 24, 2023
1 parent 0e86813 commit 5907914
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def f8(x: bytes = b"50 character byte stringgggggggggggggggggggggggggg\xff") ->

foo: str = "50 character stringggggggggggggggggggggggggggggggg"
bar: str = "51 character stringgggggggggggggggggggggggggggggggg"
baz: str = f"51 character stringgggggggggggggggggggggggggggggggg"

baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg" # OK

qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053

ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK

fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053

class Demo:
"""Docstrings are excluded from this rule. Some padding.""" # OK

Expand Down
42 changes: 30 additions & 12 deletions crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};

use ruff_diagnostics::Diagnostic;

use ruff_python_ast::node::AstNode;
use ruff_python_ast::types::Node;
use ruff_python_semantic::analyze::typing;
use ruff_python_semantic::ScopeKind;
Expand Down Expand Up @@ -968,8 +969,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
ruff::rules::explicit_f_string_type_conversion(checker, expr, elements);
}
for element in elements {
if let ast::FStringElement::Literal(ast::FStringLiteralElement { value, range }) =
element
if let ast::FStringElement::Literal(
literal_element @ ast::FStringLiteralElement { value, range },
) = element
{
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
if let Some(diagnostic) =
Expand All @@ -981,6 +983,15 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::HardcodedTempFile) {
flake8_bandit::rules::hardcoded_tmp_directory(checker, *range, value);
}

if checker.source_type.is_stub() {
if checker.enabled(Rule::StringOrBytesTooLong) {
flake8_pyi::rules::string_or_bytes_too_long(
checker,
&literal_element.as_any_node_ref(),
);
}
}
}
}
}
Expand Down Expand Up @@ -1242,18 +1253,22 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
flake8_pyi::rules::numeric_literal_too_long(checker, expr);
}
}
Expr::Constant(ast::ExprConstant {
value: Constant::Bytes(_),
range: _,
}) => {
Expr::Constant(
constant @ ast::ExprConstant {
value: Constant::Bytes(_),
range: _,
},
) => {
if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) {
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
flake8_pyi::rules::string_or_bytes_too_long(checker, &constant.as_any_node_ref());
}
}
Expr::Constant(ast::ExprConstant {
value: Constant::Str(value),
range: _,
}) => {
Expr::Constant(
constant @ ast::ExprConstant {
value: Constant::Str(value),
range: _,
},
) => {
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
if let Some(diagnostic) =
flake8_bandit::rules::hardcoded_bind_all_interfaces(value, expr.range())
Expand All @@ -1269,7 +1284,10 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
}
if checker.source_type.is_stub() {
if checker.enabled(Rule::StringOrBytesTooLong) {
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
flake8_pyi::rules::string_or_bytes_too_long(
checker,
&constant.as_any_node_ref(),
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use ruff_python_ast::{self as ast, Constant, Expr};
use ruff_python_ast::{self as ast, Constant};

use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::is_docstring_stmt;
use ruff_python_ast::node::AnyNodeRef;
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -42,32 +43,35 @@ impl AlwaysAutofixableViolation for StringOrBytesTooLong {
}

/// PYI053
pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, expr: &Expr) {
pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, node: &AnyNodeRef) {
// Ignore docstrings.
if is_docstring_stmt(checker.semantic().current_statement()) {
return;
}

let length = match expr {
Expr::Constant(ast::ExprConstant {
let length = match node {
AnyNodeRef::ExprConstant(ast::ExprConstant {
value: Constant::Str(s),
..
}) => s.chars().count(),
Expr::Constant(ast::ExprConstant {
AnyNodeRef::ExprConstant(ast::ExprConstant {
value: Constant::Bytes(bytes),
..
}) => bytes.len(),
AnyNodeRef::FStringLiteralElement(ast::FStringLiteralElement { value, .. }) => {
value.chars().count()
}
_ => return,
};
if length <= 50 {
return;
}

let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, expr.range());
let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, node.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
"...".to_string(),
expr.range(),
node.range(),
)));
}
checker.diagnostics.push(diagnostic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ PYI053.pyi:30:14: PYI053 [*] String and bytes literals longer than 50 characters
30 | qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI053
31 |
32 | class Demo:
32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK
|
= help: Replace with `...`

Expand All @@ -101,7 +101,28 @@ PYI053.pyi:30:14: PYI053 [*] String and bytes literals longer than 50 characters
30 |-qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053
30 |+qux: bytes = ... # Error: PYI053
31 31 |
32 32 | class Demo:
33 33 | """Docstrings are excluded from this rule. Some padding.""" # OK
32 32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK
33 33 |

PYI053.pyi:34:15: PYI053 [*] String and bytes literals longer than 50 characters are not permitted
|
32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK
33 |
34 | fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI053
35 |
36 | class Demo:
|
= help: Replace with `...`

Suggested fix
31 31 |
32 32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK
33 33 |
34 |-fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053
34 |+fbar: str = f"..." # Error: PYI053
35 35 |
36 36 | class Demo:
37 37 | """Docstrings are excluded from this rule. Some padding.""" # OK


0 comments on commit 5907914

Please sign in to comment.