Skip to content

Commit

Permalink
Allow top-level await in Jupyter notebooks (#6607)
Browse files Browse the repository at this point in the history
## Summary

Top-level `await` is allowed in Jupyter notebooks (see:
[autoawait](https://ipython.readthedocs.io/en/stable/interactive/autoawait.html)).

Closes #6584.

## Test Plan

Had to test this manually. Created a notebook, verified that the `yield`
was flagged but the `await` was not.

<img width="868" alt="Screen Shot 2023-08-15 at 11 40 19 PM"
src="https://github.com/astral-sh/ruff/assets/1309177/b2853651-30a6-4dc6-851c-9fe7f694b8e8">
  • Loading branch information
charliermarsh authored Aug 16, 2023
1 parent d9a81f4 commit 2d86e78
Showing 1 changed file with 21 additions and 9 deletions.
30 changes: 21 additions & 9 deletions crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use std::fmt;

use ruff_python_ast::{Expr, Ranged};

use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::ScopeKind;
use ruff_python_ast::{Expr, Ranged};

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

Expand All @@ -26,12 +24,15 @@ impl fmt::Display for DeferralKeyword {
}

/// ## What it does
/// Checks for `yield` and `yield from` statements outside of functions.
/// Checks for `yield`, `yield from`, and `await` usages outside of functions.
///
/// ## Why is this bad?
/// The use of a `yield` or `yield from` statement outside of a function will
/// The use of `yield`, `yield from`, or `await` outside of a function will
/// raise a `SyntaxError`.
///
/// As an exception, `await` is allowed at the top level of a Jupyter notebook
/// (see: [autoawait]).
///
/// ## Example
/// ```python
/// class Foo:
Expand All @@ -40,6 +41,8 @@ impl fmt::Display for DeferralKeyword {
///
/// ## References
/// - [Python documentation: `yield`](https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement)
///
/// [autoawait]: https://ipython.readthedocs.io/en/stable/interactive/autoawait.html
#[violation]
pub struct YieldOutsideFunction {
keyword: DeferralKeyword,
Expand All @@ -53,17 +56,26 @@ impl Violation for YieldOutsideFunction {
}
}

/// F704
pub(crate) fn yield_outside_function(checker: &mut Checker, expr: &Expr) {
if matches!(
checker.semantic().current_scope().kind,
ScopeKind::Class(_) | ScopeKind::Module
) {
let scope = checker.semantic().current_scope();
if scope.kind.is_module() || scope.kind.is_class() {
let keyword = match expr {
Expr::Yield(_) => DeferralKeyword::Yield,
Expr::YieldFrom(_) => DeferralKeyword::YieldFrom,
Expr::Await(_) => DeferralKeyword::Await,
_ => return,
};

// `await` is allowed at the top level of a Jupyter notebook.
// See: https://ipython.readthedocs.io/en/stable/interactive/autoawait.html.
if scope.kind.is_module()
&& checker.source_type.is_jupyter()
&& keyword == DeferralKeyword::Await
{
return;
}

checker.diagnostics.push(Diagnostic::new(
YieldOutsideFunction { keyword },
expr.range(),
Expand Down

0 comments on commit 2d86e78

Please sign in to comment.