Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable abspath(__file__) removal #336

Merged
merged 1 commit into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
| T201 | PrintFound | `print` found | | 🛠 |
| T203 | PPrintFound | `pprint` found | | 🛠 |
| U001 | UselessMetaclassType | `__metaclass__ = type` is implied | | 🛠 |
| U002 | UnnecessaryAbspath | `abspath(__file__)` is unnecessary in Python 3.9 and later | | 🛠 |
| R001 | UselessObjectInheritance | Class `...` inherits from object | | 🛠 |
| R002 | NoAssertEquals | `assertEquals` is deprecated, use `assertEqual` instead | | 🛠 |
| M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 |
Expand Down
15 changes: 15 additions & 0 deletions resources/test/fixtures/U002.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from os.path import abspath

x = abspath(__file__)


import os


y = os.path.abspath(__file__)


from os import path


z = path.abspath(__file__)
21 changes: 21 additions & 0 deletions src/ast/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,27 @@ pub fn check_useless_metaclass_type(
None
}

/// Check UnnecessaryAbspath compliance.
pub fn check_unnecessary_abspath(func: &Expr, args: &Vec<Expr>, location: Range) -> Option<Check> {
// Validate the arguments.
if args.len() == 1 {
if let ExprKind::Name { id, .. } = &args[0].node {
if id == "__file__" {
match &func.node {
ExprKind::Attribute { attr: id, .. } | ExprKind::Name { id, .. } => {
if id == "abspath" {
return Some(Check::new(CheckKind::UnnecessaryAbspath, location));
}
}
_ => {}
}
}
}
}

None
}

fn is_ambiguous_name(name: &str) -> bool {
name == "l" || name == "I" || name == "O"
}
Expand Down
5 changes: 5 additions & 0 deletions src/check_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,11 @@ where
};
}

// pyupgrade
if self.settings.enabled.contains(&CheckCode::U002) {
plugins::unnecessary_abspath(self, expr, func, args);
}

if let ExprKind::Name { id, ctx } = &func.node {
if id == "locals" && matches!(ctx, ExprContext::Load) {
let scope = &mut self.scopes[*(self
Expand Down
25 changes: 20 additions & 5 deletions src/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
CheckCode::F901,
];

pub const ALL_CHECK_CODES: [CheckCode; 53] = [
pub const ALL_CHECK_CODES: [CheckCode; 54] = [
// pycodestyle
CheckCode::E402,
CheckCode::E501,
Expand Down Expand Up @@ -111,6 +111,7 @@ pub const ALL_CHECK_CODES: [CheckCode; 53] = [
CheckCode::T203,
// pyupgrade
CheckCode::U001,
CheckCode::U002,
// Refactor
CheckCode::R001,
CheckCode::R002,
Expand Down Expand Up @@ -177,6 +178,7 @@ pub enum CheckCode {
T203,
// pyupgrade
U001,
U002,
// Refactor
R001,
R002,
Expand Down Expand Up @@ -246,6 +248,7 @@ impl FromStr for CheckCode {
"T203" => Ok(CheckCode::T203),
// pyupgrade
"U001" => Ok(CheckCode::U001),
"U002" => Ok(CheckCode::U002),
// Refactor
"R001" => Ok(CheckCode::R001),
"R002" => Ok(CheckCode::R002),
Expand Down Expand Up @@ -316,6 +319,7 @@ impl CheckCode {
CheckCode::T203 => "T203",
// pyupgrade
CheckCode::U001 => "U001",
CheckCode::U002 => "U002",
// Refactor
CheckCode::R001 => "R001",
CheckCode::R002 => "R002",
Expand Down Expand Up @@ -395,6 +399,7 @@ impl CheckCode {
CheckCode::T203 => CheckKind::PPrintFound,
// pyupgrade
CheckCode::U001 => CheckKind::UselessMetaclassType,
CheckCode::U002 => CheckKind::UnnecessaryAbspath,
// Refactor
CheckCode::R001 => CheckKind::UselessObjectInheritance("...".to_string()),
CheckCode::R002 => CheckKind::NoAssertEquals,
Expand Down Expand Up @@ -446,7 +451,6 @@ pub enum CheckKind {
ModuleImportNotAtTopOfFile,
MultiValueRepeatedKeyLiteral,
MultiValueRepeatedKeyVariable(String),
NoAssertEquals,
NoneComparison(RejectedCmpop),
NotInTest,
NotIsTest,
Expand All @@ -460,10 +464,7 @@ pub enum CheckKind {
UndefinedLocal(String),
UndefinedName(String),
UnusedImport(String),
UnusedNOQA(Option<String>),
UnusedVariable(String),
UselessMetaclassType,
UselessObjectInheritance(String),
YieldOutsideFunction,
// flake8-builtin
BuiltinVariableShadowing(String),
Expand All @@ -476,6 +477,14 @@ pub enum CheckKind {
// flake8-print
PrintFound,
PPrintFound,
// pyupgrade
UnnecessaryAbspath,
UselessMetaclassType,
// Refactor
NoAssertEquals,
UselessObjectInheritance(String),
// Meta
UnusedNOQA(Option<String>),
}

impl CheckKind {
Expand Down Expand Up @@ -536,6 +545,7 @@ impl CheckKind {
CheckKind::PrintFound => "PrintFound",
CheckKind::PPrintFound => "PPrintFound",
// pyupgrade
CheckKind::UnnecessaryAbspath => "UnnecessaryAbspath",
CheckKind::UselessMetaclassType => "UselessMetaclassType",
// Refactor
CheckKind::NoAssertEquals => "NoAssertEquals",
Expand Down Expand Up @@ -602,6 +612,7 @@ impl CheckKind {
CheckKind::PrintFound => &CheckCode::T201,
CheckKind::PPrintFound => &CheckCode::T203,
// pyupgrade
CheckKind::UnnecessaryAbspath => &CheckCode::U002,
CheckKind::UselessMetaclassType => &CheckCode::U001,
// Refactor
CheckKind::NoAssertEquals => &CheckCode::R002,
Expand Down Expand Up @@ -761,6 +772,9 @@ impl CheckKind {
CheckKind::PrintFound => "`print` found".to_string(),
CheckKind::PPrintFound => "`pprint` found".to_string(),
// pyupgrade
CheckKind::UnnecessaryAbspath => {
"`abspath(__file__)` is unnecessary in Python 3.9 and later".to_string()
}
CheckKind::UselessMetaclassType => "`__metaclass__ = type` is implied".to_string(),
// Refactor
CheckKind::NoAssertEquals => {
Expand All @@ -785,6 +799,7 @@ impl CheckKind {
| CheckKind::PPrintFound
| CheckKind::PrintFound
| CheckKind::SuperCallWithParameters
| CheckKind::UnnecessaryAbspath
| CheckKind::UnusedImport(_)
| CheckKind::UnusedNOQA(_)
| CheckKind::UselessMetaclassType
Expand Down
12 changes: 12 additions & 0 deletions src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,4 +845,16 @@ mod tests {
insta::assert_yaml_snapshot!(checks);
Ok(())
}

#[test]
fn u002() -> Result<()> {
let mut checks = check_path(
Path::new("./resources/test/fixtures/U002.py"),
&settings::Settings::for_rule(CheckCode::U002),
&fixer::Mode::Generate,
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
}
2 changes: 2 additions & 0 deletions src/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod if_tuple;
mod invalid_print_syntax;
mod print_call;
mod super_call_with_parameters;
mod unnecessary_abspath;
mod useless_metaclass_type;
mod useless_object_inheritance;

Expand All @@ -13,5 +14,6 @@ pub use if_tuple::if_tuple;
pub use invalid_print_syntax::invalid_print_syntax;
pub use print_call::print_call;
pub use super_call_with_parameters::super_call_with_parameters;
pub use unnecessary_abspath::unnecessary_abspath;
pub use useless_metaclass_type::useless_metaclass_type;
pub use useless_object_inheritance::useless_object_inheritance;
25 changes: 25 additions & 0 deletions src/plugins/unnecessary_abspath.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use rustpython_ast::Expr;

use crate::ast::checks;
use crate::ast::types::{CheckLocator, Range};
use crate::autofix::fixer;
use crate::check_ast::Checker;
use crate::checks::Fix;

pub fn unnecessary_abspath(checker: &mut Checker, expr: &Expr, func: &Expr, args: &Vec<Expr>) {
if let Some(mut check) = checks::check_unnecessary_abspath(
func,
args,
checker.locate_check(Range::from_located(expr)),
) {
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
check.amend(Fix {
content: "__file__".to_string(),
location: expr.location,
end_location: expr.end_location,
applied: false,
});
}
checker.add_check(check);
}
}