Implement pyupgrade check for io.open alias (#1399)

This commit is contained in:
Reiner Gerecke 2022-12-27 13:47:40 +01:00 committed by GitHub
parent 320a48977b
commit e0b39fa63e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 3 deletions

View File

@ -80,7 +80,7 @@ Then, run `cargo test`. Your test will fail, but you'll be prompted to follow-up
rest of your changes.
Finally, to update the documentation, run `cargo dev generate-rules-table` from the repo root. To
update the generated prefix map, run `cargo dev generate-check-code-prefix`. Both of these commands
update the generated prefix map, run `cargo +nightly dev generate-check-code-prefix`. Both of these commands
should be run whenever a new check is added to the codebase.
### Example: Adding a new configuration option

View File

@ -659,6 +659,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| UP017 | DatetimeTimezoneUTC | Use `datetime.UTC` alias | 🛠 |
| UP018 | NativeLiterals | Unnecessary call to `str` and `bytes` | 🛠 |
| UP019 | TypingTextStrAlias | `typing.Text` is deprecated, use `str` | 🛠 |
| UP020 | OpenAlias | Use builtin `open` instead | 🛠 |
### pep8-naming (N)
@ -1262,7 +1263,7 @@ natively, including:
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
- [`pydocstyle`](https://pypi.org/project/pydocstyle/)
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10)
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (19/33)
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (20/33)
- [`yesqa`](https://github.com/asottile/yesqa)
Note that, in some cases, Ruff uses different error code prefixes than would be found in the
@ -1319,7 +1320,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
Ruff can also replace [`isort`](https://pypi.org/project/isort/),
[`yesqa`](https://github.com/asottile/yesqa), [`eradicate`](https://pypi.org/project/eradicate/),
[`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10), and a subset of the rules
implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (19/33).
implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (20/33).
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.

View File

@ -0,0 +1,9 @@
from io import open
with open("f.txt") as f:
print(f.read())
import io
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
print(f.read())

View File

@ -865,6 +865,8 @@
"UP017",
"UP018",
"UP019",
"UP02",
"UP020",
"W",
"W2",
"W29",

View File

@ -1926,6 +1926,10 @@ where
pyupgrade::plugins::redundant_open_modes(self, expr);
}
if self.settings.enabled.contains(&CheckCode::UP020) {
pyupgrade::plugins::open_alias(self, expr, func);
}
// flake8-boolean-trap
if self.settings.enabled.contains(&CheckCode::FBT003) {
flake8_boolean_trap::plugins::check_boolean_positional_value_in_function_call(

View File

@ -227,6 +227,7 @@ pub enum CheckCode {
UP017,
UP018,
UP019,
UP020,
// pydocstyle
D100,
D101,
@ -839,6 +840,7 @@ pub enum CheckKind {
RemoveSixCompat,
DatetimeTimezoneUTC,
NativeLiterals,
OpenAlias,
// pydocstyle
BlankLineAfterLastSection(String),
BlankLineAfterSection(String),
@ -1215,6 +1217,7 @@ impl CheckCode {
CheckCode::UP017 => CheckKind::DatetimeTimezoneUTC,
CheckCode::UP018 => CheckKind::NativeLiterals,
CheckCode::UP019 => CheckKind::TypingTextStrAlias,
CheckCode::UP020 => CheckKind::OpenAlias,
// pydocstyle
CheckCode::D100 => CheckKind::PublicModule,
CheckCode::D101 => CheckKind::PublicClass,
@ -1635,6 +1638,7 @@ impl CheckCode {
CheckCode::UP017 => CheckCategory::Pyupgrade,
CheckCode::UP018 => CheckCategory::Pyupgrade,
CheckCode::UP019 => CheckCategory::Pyupgrade,
CheckCode::UP020 => CheckCategory::Pyupgrade,
CheckCode::W292 => CheckCategory::Pycodestyle,
CheckCode::W605 => CheckCategory::Pycodestyle,
CheckCode::YTT101 => CheckCategory::Flake82020,
@ -1848,6 +1852,7 @@ impl CheckKind {
CheckKind::DatetimeTimezoneUTC => &CheckCode::UP017,
CheckKind::NativeLiterals => &CheckCode::UP018,
CheckKind::TypingTextStrAlias => &CheckCode::UP019,
CheckKind::OpenAlias => &CheckCode::UP020,
// pydocstyle
CheckKind::BlankLineAfterLastSection(..) => &CheckCode::D413,
CheckKind::BlankLineAfterSection(..) => &CheckCode::D410,
@ -2573,6 +2578,7 @@ impl CheckKind {
CheckKind::RemoveSixCompat => "Unnecessary `six` compatibility usage".to_string(),
CheckKind::DatetimeTimezoneUTC => "Use `datetime.UTC` alias".to_string(),
CheckKind::NativeLiterals => "Unnecessary call to `str` and `bytes`".to_string(),
CheckKind::OpenAlias => "Use builtin `open` instead".to_string(),
CheckKind::ConvertTypedDictFunctionalToClass(name) => {
format!("Convert `{name}` from `TypedDict` functional to class syntax")
}
@ -3015,6 +3021,7 @@ impl CheckKind {
| CheckKind::MisplacedComparisonConstant(..)
| CheckKind::MissingReturnTypeSpecialMethod(..)
| CheckKind::NativeLiterals
| CheckKind::OpenAlias
| CheckKind::NewLineAfterLastParagraph
| CheckKind::NewLineAfterSectionName(..)
| CheckKind::NoBlankLineAfterFunction(..)

View File

@ -527,6 +527,8 @@ pub enum CheckCodePrefix {
UP017,
UP018,
UP019,
UP02,
UP020,
W,
W2,
W29,
@ -2104,6 +2106,7 @@ impl CheckCodePrefix {
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
]
}
CheckCodePrefix::U0 => {
@ -2132,6 +2135,7 @@ impl CheckCodePrefix {
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
]
}
CheckCodePrefix::U00 => {
@ -2344,6 +2348,7 @@ impl CheckCodePrefix {
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
],
CheckCodePrefix::UP0 => vec![
CheckCode::UP001,
@ -2364,6 +2369,7 @@ impl CheckCodePrefix {
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
],
CheckCodePrefix::UP00 => vec![
CheckCode::UP001,
@ -2405,6 +2411,8 @@ impl CheckCodePrefix {
CheckCodePrefix::UP017 => vec![CheckCode::UP017],
CheckCodePrefix::UP018 => vec![CheckCode::UP018],
CheckCodePrefix::UP019 => vec![CheckCode::UP019],
CheckCodePrefix::UP02 => vec![CheckCode::UP020],
CheckCodePrefix::UP020 => vec![CheckCode::UP020],
CheckCodePrefix::W => vec![CheckCode::W292, CheckCode::W605],
CheckCodePrefix::W2 => vec![CheckCode::W292],
CheckCodePrefix::W29 => vec![CheckCode::W292],
@ -2963,6 +2971,8 @@ impl CheckCodePrefix {
CheckCodePrefix::UP017 => SuffixLength::Three,
CheckCodePrefix::UP018 => SuffixLength::Three,
CheckCodePrefix::UP019 => SuffixLength::Three,
CheckCodePrefix::UP02 => SuffixLength::Two,
CheckCodePrefix::UP020 => SuffixLength::Three,
CheckCodePrefix::W => SuffixLength::Zero,
CheckCodePrefix::W2 => SuffixLength::One,
CheckCodePrefix::W29 => SuffixLength::Two,

View File

@ -3,6 +3,7 @@ pub use convert_typed_dict_functional_to_class::convert_typed_dict_functional_to
pub use datetime_utc_alias::datetime_utc_alias;
pub use deprecated_unittest_alias::deprecated_unittest_alias;
pub use native_literals::native_literals;
pub use open_alias::open_alias;
pub use redundant_open_modes::redundant_open_modes;
pub use remove_six_compat::remove_six_compat;
pub use super_call_with_parameters::super_call_with_parameters;
@ -21,6 +22,7 @@ mod convert_typed_dict_functional_to_class;
mod datetime_utc_alias;
mod deprecated_unittest_alias;
mod native_literals;
mod open_alias;
mod redundant_open_modes;
mod remove_six_compat;
mod super_call_with_parameters;

View File

@ -0,0 +1,24 @@
use rustpython_ast::Expr;
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckCode, CheckKind};
/// UP020
pub fn open_alias(checker: &mut Checker, expr: &Expr, func: &Expr) {
let call_path = dealias_call_path(collect_call_paths(expr), &checker.import_aliases);
if match_call_path(&call_path, "io", "open", &checker.from_imports) {
let mut check = Check::new(CheckKind::OpenAlias, Range::from_located(expr));
if checker.patch(&CheckCode::UP020) {
check.amend(Fix::replacement(
"open".to_string(),
func.location,
func.end_location.unwrap(),
));
}
checker.add_check(check);
}
}