Skip to content

Commit

Permalink
Implement Pylint's yield-inside-async-function rule (PLE1700) (#4668
Browse files Browse the repository at this point in the history
)
  • Loading branch information
chanman3388 committed May 27, 2023
1 parent af433ac commit 1268ddc
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
async def success():
yield 42


async def fail():
l = (1, 2, 3)
yield from l
5 changes: 4 additions & 1 deletion crates/ruff/src/checkers/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3077,13 +3077,16 @@ where
pylint::rules::yield_in_init(self, expr);
}
}
Expr::YieldFrom(_) => {
Expr::YieldFrom(yield_from) => {
if self.enabled(Rule::YieldOutsideFunction) {
pyflakes::rules::yield_outside_function(self, expr);
}
if self.enabled(Rule::YieldInInit) {
pylint::rules::yield_in_init(self, expr);
}
if self.enabled(Rule::YieldFromInAsyncFunction) {
pylint::rules::yield_from_in_async_function(self, yield_from);
}
}
Expr::Await(_) => {
if self.enabled(Rule::YieldOutsideFunction) {
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "E1307") => (RuleGroup::Unspecified, Rule::BadStringFormatType),
(Pylint, "E1310") => (RuleGroup::Unspecified, Rule::BadStrStripCall),
(Pylint, "E1507") => (RuleGroup::Unspecified, Rule::InvalidEnvvarValue),
(Pylint, "E1700") => (RuleGroup::Unspecified, Rule::YieldFromInAsyncFunction),
(Pylint, "E2502") => (RuleGroup::Unspecified, Rule::BidirectionalUnicode),
(Pylint, "E2510") => (RuleGroup::Unspecified, Rule::InvalidCharacterBackspace),
(Pylint, "E2512") => (RuleGroup::Unspecified, Rule::InvalidCharacterSub),
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ ruff_macros::register_rules!(
// pylint
rules::pylint::rules::AssertOnStringLiteral,
rules::pylint::rules::UselessReturn,
rules::pylint::rules::YieldFromInAsyncFunction,
rules::pylint::rules::YieldInInit,
rules::pylint::rules::InvalidAllObject,
rules::pylint::rules::InvalidAllFormat,
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/rules/pylint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ mod tests {
#[test_case(Rule::UselessElseOnLoop, Path::new("useless_else_on_loop.py"); "PLW0120")]
#[test_case(Rule::UselessImportAlias, Path::new("import_aliasing.py"); "PLC0414")]
#[test_case(Rule::UselessReturn, Path::new("useless_return.py"); "PLR1711")]
#[test_case(Rule::YieldFromInAsyncFunction, Path::new("yield_from_in_async_function.py"); "PLE1700")]
#[test_case(Rule::YieldInInit, Path::new("yield_in_init.py"); "PLE0100")]
#[test_case(Rule::NestedMinMax, Path::new("nested_min_max.py"); "PLW3301")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff/src/rules/pylint/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ pub(crate) use unnecessary_direct_lambda_call::{
pub(crate) use useless_else_on_loop::{useless_else_on_loop, UselessElseOnLoop};
pub(crate) use useless_import_alias::{useless_import_alias, UselessImportAlias};
pub(crate) use useless_return::{useless_return, UselessReturn};
pub(crate) use yield_from_in_async_function::{
yield_from_in_async_function, YieldFromInAsyncFunction,
};
pub(crate) use yield_in_init::{yield_in_init, YieldInInit};

mod assert_on_string_literal;
Expand Down Expand Up @@ -91,4 +94,5 @@ mod unnecessary_direct_lambda_call;
mod useless_else_on_loop;
mod useless_import_alias;
mod useless_return;
mod yield_from_in_async_function;
mod yield_in_init;
47 changes: 47 additions & 0 deletions crates/ruff/src/rules/pylint/rules/yield_from_in_async_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use rustpython_parser::ast::{ExprYieldFrom, Ranged};

use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};

use crate::checkers::ast::Checker;

/// ## What it does
/// Checks for uses of `yield from` in async functions.
///
/// ## Why is this bad?
/// Python doesn't support the use of `yield from` in async functions, and will
/// raise a `SyntaxError` in such cases.
///
/// Instead, considering refactoring the code to use an `async for` loop instead.
///
/// ## Example
/// ```python
/// async def numbers():
/// yield from [1, 2, 3, 4, 5]
/// ```
///
/// Use instead:
/// ```python
/// async def numbers():
/// async for number in [1, 2, 3, 4, 5]:
/// yield number
/// ```
#[violation]
pub struct YieldFromInAsyncFunction;

impl Violation for YieldFromInAsyncFunction {
#[derive_message_formats]
fn message(&self) -> String {
format!("`yield from` statement in async function; use `async for` instead")
}
}

/// PLE1700
pub(crate) fn yield_from_in_async_function(checker: &mut Checker, expr: &ExprYieldFrom) {
let scope = checker.semantic_model().scope();
if scope.kind.is_async_function() {
checker
.diagnostics
.push(Diagnostic::new(YieldFromInAsyncFunction, expr.range()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: crates/ruff/src/rules/pylint/mod.rs
---
yield_from_in_async_function.py:7:5: PLE1700 `yield from` statement in async function; use `async for` instead
|
7 | async def fail():
8 | l = (1, 2, 3)
9 | yield from l
| ^^^^^^^^^^^^ PLE1700
|


3 changes: 3 additions & 0 deletions ruff.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1268ddc

Please sign in to comment.