Remove Result from SourceCodeGenerator signature (#1677)

We populate this buffer ourselves, so I believe it's fine for us to use
an unchecked UTF-8 cast here. It _dramatically_ simplifies so much
downstream code.
This commit is contained in:
Charlie Marsh 2023-01-05 21:41:26 -05:00 committed by GitHub
parent ee4cae97d5
commit 8caa73df6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 274 additions and 473 deletions

View file

@ -28,6 +28,6 @@ pub fn main(cli: &Cli) -> Result<()> {
stylist.line_ending(),
);
generator.unparse_suite(&python_ast);
println!("{}", generator.generate()?);
println!("{}", generator.generate());
Ok(())
}

View file

@ -1,4 +1,3 @@
use log::error;
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind};
use crate::ast::types::Range;
@ -54,16 +53,11 @@ pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option
checker.style.line_ending(),
);
generator.unparse_stmt(&assertion_error(msg));
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
stmt.location,
stmt.end_location.unwrap(),
));
}
Err(e) => error!("Failed to rewrite `assert False`: {e}"),
};
check.amend(Fix::replacement(
generator.generate(),
stmt.location,
stmt.end_location.unwrap(),
));
}
checker.add_check(check);
}

View file

@ -1,5 +1,4 @@
use itertools::Itertools;
use log::error;
use rustc_hash::{FxHashMap, FxHashSet};
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Location};
@ -65,16 +64,11 @@ fn duplicate_handler_exceptions<'a>(
} else {
generator.unparse_expr(&type_pattern(unique_elts), 0);
}
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to remove duplicate exceptions: {e}"),
}
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}

View file

@ -1,4 +1,3 @@
use log::error;
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location};
use crate::ast::types::Range;
@ -53,16 +52,11 @@ pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
checker.style.line_ending(),
);
generator.unparse_expr(&attribute(obj, value), 0);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to rewrite `getattr`: {e}"),
}
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}

View file

@ -1,4 +1,3 @@
use log::error;
use rustpython_ast::{Excepthandler, ExcepthandlerKind, ExprKind};
use crate::ast::types::Range;
@ -30,16 +29,11 @@ pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[E
checker.style.line_ending(),
);
generator.unparse_expr(elt, 0);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
type_.location,
type_.end_location.unwrap(),
));
}
Err(e) => error!("Failed to remove redundant tuple: {e}"),
}
check.amend(Fix::replacement(
generator.generate(),
type_.location,
type_.end_location.unwrap(),
));
}
checker.add_check(check);
}

View file

@ -1,5 +1,3 @@
use anyhow::Result;
use log::error;
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind};
use crate::ast::types::Range;
@ -11,12 +9,7 @@ use crate::registry::{Check, CheckKind};
use crate::source_code_generator::SourceCodeGenerator;
use crate::source_code_style::SourceCodeStyleDetector;
fn assignment(
obj: &Expr,
name: &str,
value: &Expr,
stylist: &SourceCodeStyleDetector,
) -> Result<String> {
fn assignment(obj: &Expr, name: &str, value: &Expr, stylist: &SourceCodeStyleDetector) -> String {
let stmt = Stmt::new(
Location::default(),
Location::default(),
@ -40,7 +33,7 @@ fn assignment(
stylist.line_ending(),
);
generator.unparse_stmt(&stmt);
generator.generate().map_err(std::convert::Into::into)
generator.generate()
}
/// B010
@ -73,16 +66,11 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
if expr == child.as_ref() {
let mut check = Check::new(CheckKind::SetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
match assignment(obj, name, value, checker.style) {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to fix invalid comparison: {e}"),
};
check.amend(Fix::replacement(
assignment(obj, name, value, checker.style),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}

View file

@ -1,4 +1,3 @@
use log::error;
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind};
use super::helpers::is_pytest_parametrize;
@ -36,7 +35,6 @@ fn elts_to_csv(elts: &[Expr], checker: &Checker) -> Option<String> {
checker.style.quote(),
checker.style.line_ending(),
);
generator.unparse_expr(
&create_expr(ExprKind::Constant {
value: Constant::Str(elts.iter().fold(String::new(), |mut acc, elt| {
@ -56,17 +54,7 @@ fn elts_to_csv(elts: &[Expr], checker: &Checker) -> Option<String> {
}),
0,
);
match generator.generate() {
Ok(s) => Some(s),
Err(e) => {
error!(
"Failed to generate CSV string from sequence of names: {}",
e
);
None
}
}
Some(generator.generate())
}
/// PT006
@ -120,19 +108,11 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}),
1,
);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!(
"Failed to fix wrong name(s) type in \
`@pytest.mark.parametrize`: {e}"
),
};
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}
@ -162,19 +142,11 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}),
0,
);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!(
"Failed to fix wrong name(s) type in \
`@pytest.mark.parametrize`: {e}"
),
};
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}
@ -208,19 +180,11 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}),
0,
);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!(
"Failed to fix wrong name(s) type in \
`@pytest.mark.parametrize`: {e}"
),
};
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}
@ -269,19 +233,11 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}),
1, // so tuple is generated with parentheses
);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!(
"Failed to fix wrong name(s) type in \
`@pytest.mark.parametrize`: {e}"
),
};
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}
@ -353,16 +309,11 @@ fn handle_single_name(checker: &mut Checker, expr: &Expr, value: &Expr) {
checker.style.line_ending(),
);
generator.unparse_expr(&create_expr(value.node.clone()), 0);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to fix wrong name(s) type in `@pytest.mark.parametrize`: {e}"),
};
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}

View file

@ -30,7 +30,7 @@ fn to_source(expr: &Expr, stylist: &SourceCodeStyleDetector) -> String {
stylist.line_ending(),
);
generator.unparse_expr(expr, 0);
generator.generate().unwrap()
generator.generate()
}
/// SIM101

View file

@ -1,4 +1,3 @@
use log::error;
use rustpython_ast::{
Comprehension, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind, Unaryop,
};
@ -83,7 +82,7 @@ fn return_stmt(
target: &Expr,
iter: &Expr,
stylist: &SourceCodeStyleDetector,
) -> Option<String> {
) -> String {
let mut generator = SourceCodeGenerator::new(
stylist.indentation(),
stylist.quote(),
@ -107,13 +106,7 @@ fn return_stmt(
keywords: vec![],
}))),
}));
match generator.generate() {
Ok(test) => Some(test),
Err(e) => {
error!("Failed to generate source code: {}", e);
None
}
}
generator.generate()
}
/// SIM110, SIM111
@ -121,26 +114,25 @@ pub fn convert_loop_to_any_all(checker: &mut Checker, stmt: &Stmt, sibling: &Stm
if let Some(loop_info) = return_values(stmt, sibling) {
if loop_info.return_value && !loop_info.next_return_value {
if checker.settings.enabled.contains(&CheckCode::SIM110) {
if let Some(content) = return_stmt(
let content = return_stmt(
"any",
loop_info.test,
loop_info.target,
loop_info.iter,
checker.style,
) {
let mut check = Check::new(
CheckKind::ConvertLoopToAny(content.clone()),
Range::from_located(stmt),
);
if checker.patch(&CheckCode::SIM110) {
check.amend(Fix::replacement(
content,
stmt.location,
sibling.end_location.unwrap(),
));
}
checker.add_check(check);
);
let mut check = Check::new(
CheckKind::ConvertLoopToAny(content.clone()),
Range::from_located(stmt),
);
if checker.patch(&CheckCode::SIM110) {
check.amend(Fix::replacement(
content,
stmt.location,
sibling.end_location.unwrap(),
));
}
checker.add_check(check);
}
}
@ -161,26 +153,25 @@ pub fn convert_loop_to_any_all(checker: &mut Checker, stmt: &Stmt, sibling: &Stm
})
}
};
if let Some(content) = return_stmt(
let content = return_stmt(
"all",
&test,
loop_info.target,
loop_info.iter,
checker.style,
) {
let mut check = Check::new(
CheckKind::ConvertLoopToAll(content.clone()),
Range::from_located(stmt),
);
if checker.patch(&CheckCode::SIM111) {
check.amend(Fix::replacement(
content,
stmt.location,
sibling.end_location.unwrap(),
));
}
checker.add_check(check);
);
let mut check = Check::new(
CheckKind::ConvertLoopToAll(content.clone()),
Range::from_located(stmt),
);
if checker.patch(&CheckCode::SIM111) {
check.amend(Fix::replacement(
content,
stmt.location,
sibling.end_location.unwrap(),
));
}
checker.add_check(check);
}
}
}

View file

@ -1,6 +1,4 @@
use anyhow::Result;
use itertools::izip;
use log::error;
use rustc_hash::FxHashMap;
use rustpython_ast::{Arguments, Location, StmtKind};
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Stmt, Unaryop};
@ -20,7 +18,7 @@ fn compare(
ops: &[Cmpop],
comparators: &[Expr],
stylist: &SourceCodeStyleDetector,
) -> Option<String> {
) -> String {
let cmp = Expr::new(
Location::default(),
Location::default(),
@ -36,7 +34,7 @@ fn compare(
stylist.line_ending(),
);
generator.unparse_expr(&cmp, 0);
generator.generate().ok()
generator.generate()
}
/// E711, E712
@ -204,14 +202,13 @@ pub fn literal_comparisons(
.map(|(idx, op)| bad_ops.get(&idx).unwrap_or(op))
.cloned()
.collect::<Vec<_>>();
if let Some(content) = compare(left, &ops, comparators, checker.style) {
for check in &mut checks {
check.amend(Fix::replacement(
content.to_string(),
expr.location,
expr.end_location.unwrap(),
));
}
let content = compare(left, &ops, comparators, checker.style);
for check in &mut checks {
check.amend(Fix::replacement(
content.to_string(),
expr.location,
expr.end_location.unwrap(),
));
}
}
@ -243,15 +240,11 @@ pub fn not_tests(
let mut check =
Check::new(CheckKind::NotInTest, Range::from_located(operand));
if checker.patch(check.kind.code()) && should_fix {
if let Some(content) =
compare(left, &[Cmpop::NotIn], comparators, checker.style)
{
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
check.amend(Fix::replacement(
compare(left, &[Cmpop::NotIn], comparators, checker.style),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}
@ -261,15 +254,11 @@ pub fn not_tests(
let mut check =
Check::new(CheckKind::NotIsTest, Range::from_located(operand));
if checker.patch(check.kind.code()) && should_fix {
if let Some(content) =
compare(left, &[Cmpop::IsNot], comparators, checker.style)
{
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
check.amend(Fix::replacement(
compare(left, &[Cmpop::IsNot], comparators, checker.style),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
}
@ -286,7 +275,7 @@ fn function(
args: &Arguments,
body: &Expr,
stylist: &SourceCodeStyleDetector,
) -> Result<String> {
) -> String {
let body = Stmt::new(
Location::default(),
Location::default(),
@ -312,7 +301,7 @@ fn function(
stylist.line_ending(),
);
generator.unparse_stmt(&func);
Ok(generator.generate()?)
generator.generate()
}
/// E731
@ -327,31 +316,26 @@ pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr,
if !match_leading_content(stmt, checker.locator)
&& !match_trailing_content(stmt, checker.locator)
{
match function(id, args, body, checker.style) {
Ok(content) => {
let first_line = checker.locator.slice_source_code_range(&Range::new(
Location::new(stmt.location.row(), 0),
Location::new(stmt.location.row() + 1, 0),
));
let indentation = &leading_space(&first_line);
let mut indented = String::new();
for (idx, line) in content.lines().enumerate() {
if idx == 0 {
indented.push_str(line);
} else {
indented.push('\n');
indented.push_str(indentation);
indented.push_str(line);
}
}
check.amend(Fix::replacement(
indented,
stmt.location,
stmt.end_location.unwrap(),
));
let first_line = checker.locator.slice_source_code_range(&Range::new(
Location::new(stmt.location.row(), 0),
Location::new(stmt.location.row() + 1, 0),
));
let indentation = &leading_space(&first_line);
let mut indented = String::new();
for (idx, line) in function(id, args, body, checker.style).lines().enumerate() {
if idx == 0 {
indented.push_str(line);
} else {
indented.push('\n');
indented.push_str(indentation);
indented.push_str(line);
}
Err(e) => error!("Failed to generate fix: {e}"),
}
check.amend(Fix::replacement(
indented,
stmt.location,
stmt.end_location.unwrap(),
));
}
}
checker.add_check(check);

View file

@ -165,19 +165,18 @@ fn convert_to_class(
body: Vec<Stmt>,
base_class: &ExprKind,
stylist: &SourceCodeStyleDetector,
) -> Result<Fix> {
) -> Fix {
let mut generator = SourceCodeGenerator::new(
stylist.indentation(),
stylist.quote(),
stylist.line_ending(),
);
generator.unparse_stmt(&create_class_def_stmt(typename, body, base_class));
let content = generator.generate()?;
Ok(Fix::replacement(
content,
Fix::replacement(
generator.generate(),
stmt.location,
stmt.end_location.unwrap(),
))
)
}
/// UP014
@ -200,12 +199,13 @@ pub fn convert_named_tuple_functional_to_class(
Range::from_located(stmt),
);
if checker.patch(check.kind.code()) {
match convert_to_class(stmt, typename, properties, base_class, checker.style) {
Ok(fix) => {
check.amend(fix);
}
Err(err) => error!("Failed to convert `NamedTuple`: {err}"),
}
check.amend(convert_to_class(
stmt,
typename,
properties,
base_class,
checker.style,
));
}
checker.add_check(check);
}

View file

@ -198,7 +198,7 @@ fn convert_to_class(
total_keyword: Option<KeywordData>,
base_class: &ExprKind,
stylist: &SourceCodeStyleDetector,
) -> Result<Fix> {
) -> Fix {
let mut generator = SourceCodeGenerator::new(
stylist.indentation(),
stylist.quote(),
@ -210,12 +210,11 @@ fn convert_to_class(
total_keyword,
base_class,
));
let content = generator.generate()?;
Ok(Fix::replacement(
content,
Fix::replacement(
generator.generate(),
stmt.location,
stmt.end_location.unwrap(),
))
)
}
/// UP013
@ -242,19 +241,14 @@ pub fn convert_typed_dict_functional_to_class(
Range::from_located(stmt),
);
if checker.patch(check.kind.code()) {
match convert_to_class(
check.amend(convert_to_class(
stmt,
class_name,
body,
total_keyword,
base_class,
checker.style,
) {
Ok(fix) => {
check.amend(fix);
}
Err(err) => error!("Failed to convert TypedDict: {err}"),
};
));
}
checker.add_check(check);
}

View file

@ -1,5 +1,3 @@
use anyhow::{bail, Result};
use log::error;
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Keyword, StmtKind};
use crate::ast::helpers::{collect_call_paths, create_expr, create_stmt, dealias_call_path};
@ -89,7 +87,7 @@ fn replace_call_on_arg_by_arg_attribute(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Check> {
) -> Check {
let attribute = ExprKind::Attribute {
value: Box::new(arg.clone()),
attr: attr.to_string(),
@ -105,11 +103,10 @@ fn replace_call_on_arg_by_arg_method_call(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Option<Check>> {
) -> Option<Check> {
if args.is_empty() {
bail!("Expected at least one argument");
}
if let ([arg], other_args) = args.split_at(1) {
None
} else if let ([arg], other_args) = args.split_at(1) {
let call = ExprKind::Call {
func: Box::new(create_expr(ExprKind::Attribute {
value: Box::new(arg.clone()),
@ -122,10 +119,9 @@ fn replace_call_on_arg_by_arg_method_call(
.collect(),
keywords: vec![],
};
let expr = replace_by_expr_kind(call, expr, patch, stylist)?;
Ok(Some(expr))
Some(replace_by_expr_kind(call, expr, patch, stylist))
} else {
Ok(None)
None
}
}
@ -135,7 +131,7 @@ fn replace_by_expr_kind(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Check> {
) -> Check {
let mut check = Check::new(CheckKind::RemoveSixCompat, Range::from_located(expr));
if patch {
let mut generator = SourceCodeGenerator::new(
@ -144,14 +140,13 @@ fn replace_by_expr_kind(
stylist.line_ending(),
);
generator.unparse_expr(&create_expr(node), 0);
let content = generator.generate()?;
check.amend(Fix::replacement(
content,
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
Ok(check)
check
}
fn replace_by_stmt_kind(
@ -159,7 +154,7 @@ fn replace_by_stmt_kind(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Check> {
) -> Check {
let mut check = Check::new(CheckKind::RemoveSixCompat, Range::from_located(expr));
if patch {
let mut generator = SourceCodeGenerator::new(
@ -168,14 +163,13 @@ fn replace_by_stmt_kind(
stylist.line_ending(),
);
generator.unparse_stmt(&create_stmt(node));
let content = generator.generate()?;
check.amend(Fix::replacement(
content,
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
Ok(check)
check
}
// => `raise exc from cause`
@ -185,7 +179,7 @@ fn replace_by_raise_from(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Check> {
) -> Check {
let stmt_kind = StmtKind::Raise {
exc: exc.map(|exc| Box::new(create_expr(exc))),
cause: cause.map(|cause| Box::new(create_expr(cause))),
@ -199,7 +193,7 @@ fn replace_by_index_on_arg(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Check> {
) -> Check {
let index = ExprKind::Subscript {
value: Box::new(create_expr(arg.node.clone())),
slice: Box::new(create_expr(index.clone())),
@ -213,7 +207,7 @@ fn handle_reraise(
expr: &Expr,
patch: bool,
stylist: &SourceCodeStyleDetector,
) -> Result<Option<Check>> {
) -> Option<Check> {
if let [_, exc, tb] = args {
let check = replace_by_raise_from(
Some(ExprKind::Call {
@ -229,24 +223,24 @@ fn handle_reraise(
expr,
patch,
stylist,
)?;
Ok(Some(check))
);
Some(check)
} else if let [arg] = args {
if let ExprKind::Starred { value, .. } = &arg.node {
if let ExprKind::Call { func, .. } = &value.node {
if let ExprKind::Attribute { value, attr, .. } = &func.node {
if let ExprKind::Name { id, .. } = &value.node {
if id == "sys" && attr == "exc_info" {
let check = replace_by_raise_from(None, None, expr, patch, stylist)?;
return Ok(Some(check));
let check = replace_by_raise_from(None, None, expr, patch, stylist);
return Some(check);
};
};
};
};
};
Ok(None)
None
} else {
Ok(None)
None
}
}
@ -258,11 +252,11 @@ fn handle_func(
patch: bool,
stylist: &SourceCodeStyleDetector,
locator: &SourceCodeLocator,
) -> Result<Option<Check>> {
) -> Option<Check> {
let func_name = match &func.node {
ExprKind::Attribute { attr, .. } => attr,
ExprKind::Name { id, .. } => id,
_ => bail!("Unexpected func: {:?}", func),
_ => return None,
};
let check = match (func_name.as_str(), args, keywords) {
("b", [arg], []) => replace_by_str_literal(arg, true, expr, patch, locator),
@ -271,73 +265,67 @@ fn handle_func(
("ensure_str", [arg], []) => replace_by_str_literal(arg, false, expr, patch, locator),
("ensure_text", [arg], []) => replace_by_str_literal(arg, false, expr, patch, locator),
("iteritems", args, []) => {
replace_call_on_arg_by_arg_method_call("items", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("items", args, expr, patch, stylist)
}
("viewitems", args, []) => {
replace_call_on_arg_by_arg_method_call("items", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("items", args, expr, patch, stylist)
}
("iterkeys", args, []) => {
replace_call_on_arg_by_arg_method_call("keys", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("keys", args, expr, patch, stylist)
}
("viewkeys", args, []) => {
replace_call_on_arg_by_arg_method_call("keys", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("keys", args, expr, patch, stylist)
}
("itervalues", args, []) => {
replace_call_on_arg_by_arg_method_call("values", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("values", args, expr, patch, stylist)
}
("viewvalues", args, []) => {
replace_call_on_arg_by_arg_method_call("values", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("values", args, expr, patch, stylist)
}
("get_method_function", [arg], []) => Some(replace_call_on_arg_by_arg_attribute(
"__func__", arg, expr, patch, stylist,
)?),
)),
("get_method_self", [arg], []) => Some(replace_call_on_arg_by_arg_attribute(
"__self__", arg, expr, patch, stylist,
)?),
)),
("get_function_closure", [arg], []) => Some(replace_call_on_arg_by_arg_attribute(
"__closure__",
arg,
expr,
patch,
stylist,
)?),
)),
("get_function_code", [arg], []) => Some(replace_call_on_arg_by_arg_attribute(
"__code__", arg, expr, patch, stylist,
)?),
)),
("get_function_defaults", [arg], []) => Some(replace_call_on_arg_by_arg_attribute(
"__defaults__",
arg,
expr,
patch,
stylist,
)?),
)),
("get_function_globals", [arg], []) => Some(replace_call_on_arg_by_arg_attribute(
"__globals__",
arg,
expr,
patch,
stylist,
)?),
("create_unbound_method", [arg, _], _) => Some(replace_by_expr_kind(
arg.node.clone(),
expr,
patch,
stylist,
)?),
("get_unbound_function", [arg], []) => Some(replace_by_expr_kind(
arg.node.clone(),
expr,
patch,
stylist,
)?),
)),
("create_unbound_method", [arg, _], _) => {
Some(replace_by_expr_kind(arg.node.clone(), expr, patch, stylist))
}
("get_unbound_function", [arg], []) => {
Some(replace_by_expr_kind(arg.node.clone(), expr, patch, stylist))
}
("assertCountEqual", args, []) => {
replace_call_on_arg_by_arg_method_call("assertCountEqual", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("assertCountEqual", args, expr, patch, stylist)
}
("assertRaisesRegex", args, []) => {
replace_call_on_arg_by_arg_method_call("assertRaisesRegex", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("assertRaisesRegex", args, expr, patch, stylist)
}
("assertRegex", args, []) => {
replace_call_on_arg_by_arg_method_call("assertRegex", args, expr, patch, stylist)?
replace_call_on_arg_by_arg_method_call("assertRegex", args, expr, patch, stylist)
}
("raise_from", [exc, cause], []) => Some(replace_by_raise_from(
Some(exc.node.clone()),
@ -345,8 +333,8 @@ fn handle_func(
expr,
patch,
stylist,
)?),
("reraise", args, []) => handle_reraise(args, expr, patch, stylist)?,
)),
("reraise", args, []) => handle_reraise(args, expr, patch, stylist),
("byte2int", [arg], []) => Some(replace_by_index_on_arg(
arg,
&ExprKind::Constant {
@ -356,14 +344,14 @@ fn handle_func(
expr,
patch,
stylist,
)?),
)),
("indexbytes", [arg, index], []) => Some(replace_by_index_on_arg(
arg,
&index.node,
expr,
patch,
stylist,
)?),
)),
("int2byte", [arg], []) => Some(replace_by_expr_kind(
ExprKind::Call {
func: Box::new(create_expr(ExprKind::Name {
@ -379,37 +367,37 @@ fn handle_func(
expr,
patch,
stylist,
)?),
)),
_ => None,
};
Ok(check)
check
}
fn handle_next_on_six_dict(expr: &Expr, patch: bool, checker: &Checker) -> Result<Option<Check>> {
fn handle_next_on_six_dict(expr: &Expr, patch: bool, checker: &Checker) -> Option<Check> {
let ExprKind::Call { func, args, .. } = &expr.node else {
return Ok(None);
return None;
};
let ExprKind::Name { id, .. } = &func.node else {
return Ok(None);
return None;
};
if id != "next" {
return Ok(None);
return None;
}
let [arg] = &args[..] else { return Ok(None); };
let [arg] = &args[..] else { return None; };
let call_path = dealias_call_path(collect_call_paths(arg), &checker.import_aliases);
if !is_module_member(&call_path, "six") {
return Ok(None);
return None;
}
let ExprKind::Call { func, args, .. } = &arg.node else {return Ok(None);};
let ExprKind::Attribute { attr, .. } = &func.node else {return Ok(None);};
let [dict_arg] = &args[..] else {return Ok(None);};
let ExprKind::Call { func, args, .. } = &arg.node else {return None;};
let ExprKind::Attribute { attr, .. } = &func.node else {return None;};
let [dict_arg] = &args[..] else {return None;};
let method_name = match attr.as_str() {
"iteritems" => "items",
"iterkeys" => "keys",
"itervalues" => "values",
_ => return Ok(None),
_ => return None,
};
match replace_by_expr_kind(
Some(replace_by_expr_kind(
ExprKind::Call {
func: Box::new(create_expr(ExprKind::Name {
id: "iter".to_string(),
@ -429,25 +417,16 @@ fn handle_next_on_six_dict(expr: &Expr, patch: bool, checker: &Checker) -> Resul
arg,
patch,
checker.style,
) {
Ok(check) => Ok(Some(check)),
Err(err) => Err(err),
}
))
}
/// UP016
pub fn remove_six_compat(checker: &mut Checker, expr: &Expr) {
match handle_next_on_six_dict(expr, checker.patch(&CheckCode::UP016), checker) {
Ok(Some(check)) => {
checker.add_check(check);
return;
}
Ok(None) => (),
Err(err) => {
error!("Error while removing `six` reference: {}", err);
return;
}
};
if let Some(check) = handle_next_on_six_dict(expr, checker.patch(&CheckCode::UP016), checker) {
checker.add_check(check);
return;
}
let call_path = dealias_call_path(collect_call_paths(expr), &checker.import_aliases);
if is_module_member(&call_path, "six") {
let patch = checker.patch(&CheckCode::UP016);
@ -456,7 +435,7 @@ pub fn remove_six_compat(checker: &mut Checker, expr: &Expr) {
func,
args,
keywords,
} => match handle_func(
} => handle_func(
func,
args,
keywords,
@ -464,13 +443,7 @@ pub fn remove_six_compat(checker: &mut Checker, expr: &Expr) {
patch,
checker.style,
checker.locator,
) {
Ok(check) => check,
Err(err) => {
error!("Failed to remove `six` reference: {err}");
return;
}
},
),
ExprKind::Attribute { attr, .. } => map_name(attr.as_str(), expr, patch),
ExprKind::Name { id, .. } => map_name(id.as_str(), expr, patch),
_ => return,

View file

@ -1,4 +1,3 @@
use log::error;
use rustpython_ast::{Constant, Expr, ExprKind, Location, Operator};
use crate::ast::helpers::{collect_call_paths, dealias_call_path};
@ -72,16 +71,11 @@ pub fn use_pep604_annotation(checker: &mut Checker, expr: &Expr, value: &Expr, s
checker.style.line_ending(),
);
generator.unparse_expr(&optional(slice), 0);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to rewrite PEP604 annotation: {e}"),
};
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
checker.add_check(check);
} else if checker.match_typing_call_path(&call_path, "Union") {
@ -98,16 +92,11 @@ pub fn use_pep604_annotation(checker: &mut Checker, expr: &Expr, value: &Expr, s
checker.style.line_ending(),
);
generator.unparse_expr(&union(elts), 0);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to rewrite PEP604 annotation: {e}"),
}
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
_ => {
// Single argument.
@ -117,16 +106,11 @@ pub fn use_pep604_annotation(checker: &mut Checker, expr: &Expr, value: &Expr, s
checker.style.line_ending(),
);
generator.unparse_expr(slice, 0);
match generator.generate() {
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to rewrite PEP604 annotation: {e}"),
}
check.amend(Fix::replacement(
generator.generate(),
expr.location,
expr.end_location.unwrap(),
));
}
}
}

View file

@ -182,64 +182,34 @@ impl Settings {
// Plugins
flake8_annotations: config
.flake8_annotations
.map(std::convert::Into::into)
.unwrap_or_default(),
flake8_bandit: config
.flake8_bandit
.map(std::convert::Into::into)
.unwrap_or_default(),
flake8_bugbear: config
.flake8_bugbear
.map(std::convert::Into::into)
.unwrap_or_default(),
flake8_errmsg: config
.flake8_errmsg
.map(std::convert::Into::into)
.map(Into::into)
.unwrap_or_default(),
flake8_bandit: config.flake8_bandit.map(Into::into).unwrap_or_default(),
flake8_bugbear: config.flake8_bugbear.map(Into::into).unwrap_or_default(),
flake8_errmsg: config.flake8_errmsg.map(Into::into).unwrap_or_default(),
flake8_import_conventions: config
.flake8_import_conventions
.map(std::convert::Into::into)
.map(Into::into)
.unwrap_or_default(),
flake8_pytest_style: config
.flake8_pytest_style
.map(std::convert::Into::into)
.unwrap_or_default(),
flake8_quotes: config
.flake8_quotes
.map(std::convert::Into::into)
.map(Into::into)
.unwrap_or_default(),
flake8_quotes: config.flake8_quotes.map(Into::into).unwrap_or_default(),
flake8_tidy_imports: config
.flake8_tidy_imports
.map(std::convert::Into::into)
.map(Into::into)
.unwrap_or_default(),
flake8_unused_arguments: config
.flake8_unused_arguments
.map(std::convert::Into::into)
.unwrap_or_default(),
isort: config
.isort
.map(std::convert::Into::into)
.unwrap_or_default(),
mccabe: config
.mccabe
.map(std::convert::Into::into)
.unwrap_or_default(),
pep8_naming: config
.pep8_naming
.map(std::convert::Into::into)
.unwrap_or_default(),
pycodestyle: config
.pycodestyle
.map(std::convert::Into::into)
.unwrap_or_default(),
pydocstyle: config
.pydocstyle
.map(std::convert::Into::into)
.unwrap_or_default(),
pyupgrade: config
.pyupgrade
.map(std::convert::Into::into)
.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(),
pycodestyle: config.pycodestyle.map(Into::into).unwrap_or_default(),
pydocstyle: config.pydocstyle.map(Into::into).unwrap_or_default(),
pyupgrade: config.pyupgrade.map(Into::into).unwrap_or_default(),
})
}
@ -393,7 +363,7 @@ pub fn resolve_globset(patterns: Vec<FilePattern>) -> Result<GlobSet> {
for pattern in patterns {
pattern.add_to(&mut builder)?;
}
builder.build().map_err(std::convert::Into::into)
builder.build().map_err(Into::into)
}
/// Given a list of patterns, create a `GlobSet`.

View file

@ -31,13 +31,13 @@ impl Pyproject {
/// Parse a `ruff.toml` file.
fn parse_ruff_toml<P: AsRef<Path>>(path: P) -> Result<Options> {
let contents = fs::read_file(path)?;
toml::from_str(&contents).map_err(std::convert::Into::into)
toml::from_str(&contents).map_err(Into::into)
}
/// Parse a `pyproject.toml` file.
fn parse_pyproject_toml<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
let contents = fs::read_file(path)?;
toml::from_str(&contents).map_err(std::convert::Into::into)
toml::from_str(&contents).map_err(Into::into)
}
/// Return `true` if a `pyproject.toml` contains a `[tool.ruff]` section.

View file

@ -2,9 +2,7 @@
use std::fmt;
use std::ops::Deref;
use std::string::FromUtf8Error;
use anyhow::Result;
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Suite, Withitem};
use rustpython_parser::ast::{
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, ConversionFlag, Expr, ExprKind,
@ -60,8 +58,8 @@ impl<'a> SourceCodeGenerator<'a> {
}
}
pub fn generate(self) -> Result<String, FromUtf8Error> {
String::from_utf8(self.buffer)
pub fn generate(self) -> String {
String::from_utf8(self.buffer).expect("Generated source code is not valid UTF-8")
}
fn newline(&mut self) {
@ -1030,21 +1028,20 @@ impl<'a> SourceCodeGenerator<'a> {
#[cfg(test)]
mod tests {
use anyhow::Result;
use rustpython_parser::parser;
use crate::source_code_generator::SourceCodeGenerator;
use crate::source_code_style::{Indentation, LineEnding, Quote};
fn round_trip(contents: &str) -> Result<String> {
fn round_trip(contents: &str) -> String {
let indentation = Indentation::default();
let quote = Quote::default();
let line_ending = LineEnding::default();
let program = parser::parse_program(contents, "<filename>")?;
let program = parser::parse_program(contents, "<filename>").unwrap();
let stmt = program.first().unwrap();
let mut generator = SourceCodeGenerator::new(&indentation, &quote, &line_ending);
generator.unparse_stmt(stmt);
generator.generate().map_err(std::convert::Into::into)
generator.generate()
}
fn round_trip_with(
@ -1052,30 +1049,29 @@ mod tests {
quote: &Quote,
line_ending: &LineEnding,
contents: &str,
) -> Result<String> {
let program = parser::parse_program(contents, "<filename>")?;
) -> String {
let program = parser::parse_program(contents, "<filename>").unwrap();
let stmt = program.first().unwrap();
let mut generator = SourceCodeGenerator::new(indentation, quote, line_ending);
generator.unparse_stmt(stmt);
generator.generate().map_err(std::convert::Into::into)
generator.generate()
}
#[test]
fn quote() -> Result<()> {
assert_eq!(round_trip(r#""hello""#)?, r#""hello""#);
assert_eq!(round_trip(r#"'hello'"#)?, r#""hello""#);
assert_eq!(round_trip(r#"u'hello'"#)?, r#"u"hello""#);
assert_eq!(round_trip(r#"r'hello'"#)?, r#""hello""#);
assert_eq!(round_trip(r#"b'hello'"#)?, r#"b"hello""#);
assert_eq!(round_trip(r#"("abc" "def" "ghi")"#)?, r#""abcdefghi""#);
assert_eq!(round_trip(r#""he\"llo""#)?, r#"'he"llo'"#);
assert_eq!(round_trip(r#"f'abc{"def"}{1}'"#)?, r#"f'abc{"def"}{1}'"#);
assert_eq!(round_trip(r#"f"abc{'def'}{1}""#)?, r#"f'abc{"def"}{1}'"#);
Ok(())
fn quote() {
assert_eq!(round_trip(r#""hello""#), r#""hello""#);
assert_eq!(round_trip(r#"'hello'"#), r#""hello""#);
assert_eq!(round_trip(r#"u'hello'"#), r#"u"hello""#);
assert_eq!(round_trip(r#"r'hello'"#), r#""hello""#);
assert_eq!(round_trip(r#"b'hello'"#), r#"b"hello""#);
assert_eq!(round_trip(r#"("abc" "def" "ghi")"#), r#""abcdefghi""#);
assert_eq!(round_trip(r#""he\"llo""#), r#"'he"llo'"#);
assert_eq!(round_trip(r#"f'abc{"def"}{1}'"#), r#"f'abc{"def"}{1}'"#);
assert_eq!(round_trip(r#"f"abc{'def'}{1}""#), r#"f'abc{"def"}{1}'"#);
}
#[test]
fn indent() -> Result<()> {
fn indent() {
assert_eq!(
round_trip(
r#"
@ -1083,25 +1079,24 @@ if True:
pass
"#
.trim(),
)?,
),
r#"
if True:
pass
"#
.trim()
);
Ok(())
}
#[test]
fn set_quote() -> Result<()> {
fn set_quote() {
assert_eq!(
round_trip_with(
&Indentation::default(),
&Quote::Double,
&LineEnding::default(),
r#""hello""#
)?,
),
r#""hello""#
);
assert_eq!(
@ -1110,7 +1105,7 @@ if True:
&Quote::Single,
&LineEnding::default(),
r#""hello""#
)?,
),
r#"'hello'"#
);
assert_eq!(
@ -1119,7 +1114,7 @@ if True:
&Quote::Double,
&LineEnding::default(),
r#"'hello'"#
)?,
),
r#""hello""#
);
assert_eq!(
@ -1128,14 +1123,13 @@ if True:
&Quote::Single,
&LineEnding::default(),
r#"'hello'"#
)?,
),
r#"'hello'"#
);
Ok(())
}
#[test]
fn set_indent() -> Result<()> {
fn set_indent() {
assert_eq!(
round_trip_with(
&Indentation::new(" ".to_string()),
@ -1146,7 +1140,7 @@ if True:
pass
"#
.trim(),
)?,
),
r#"
if True:
pass
@ -1163,7 +1157,7 @@ if True:
pass
"#
.trim(),
)?,
),
r#"
if True:
pass
@ -1180,26 +1174,24 @@ if True:
pass
"#
.trim(),
)?,
),
r#"
if True:
pass
"#
.trim()
);
Ok(())
}
#[test]
fn set_line_ending() -> Result<()> {
fn set_line_ending() {
assert_eq!(
round_trip_with(
&Indentation::default(),
&Quote::default(),
&LineEnding::Lf,
"if True:\n print(42)",
)?,
),
"if True:\n print(42)",
);
@ -1209,7 +1201,7 @@ if True:
&Quote::default(),
&LineEnding::CrLf,
"if True:\n print(42)",
)?,
),
"if True:\r\n print(42)",
);
@ -1219,10 +1211,8 @@ if True:
&Quote::default(),
&LineEnding::Cr,
"if True:\n print(42)",
)?,
),
"if True:\r print(42)",
);
Ok(())
}
}