Integrate the new Jupyter AST nodes in Ruff (#6086)

## Summary

This PR adds the implementation for the new Jupyter AST nodes i.e.,
`ExprLineMagic` and `StmtLineMagic`.

## Test Plan

Add test cases for `unparse` containing magic commands

resolves: #6087
This commit is contained in:
Dhruv Manilawala 2023-07-26 13:50:30 +05:30 committed by GitHub
parent 1fdadee59c
commit 025fa4eba8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 228 additions and 19 deletions

12
Cargo.lock generated
View file

@ -2210,7 +2210,7 @@ dependencies = [
[[package]]
name = "ruff_text_size"
version = "0.0.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=4d03b9b5b212fc869e4cfda151414438186a7779#4d03b9b5b212fc869e4cfda151414438186a7779"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72#5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72"
dependencies = [
"schemars",
"serde",
@ -2312,7 +2312,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=4d03b9b5b212fc869e4cfda151414438186a7779#4d03b9b5b212fc869e4cfda151414438186a7779"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72#5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72"
dependencies = [
"is-macro",
"num-bigint",
@ -2323,7 +2323,7 @@ dependencies = [
[[package]]
name = "rustpython-format"
version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=4d03b9b5b212fc869e4cfda151414438186a7779#4d03b9b5b212fc869e4cfda151414438186a7779"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72#5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72"
dependencies = [
"bitflags 2.3.3",
"itertools",
@ -2335,7 +2335,7 @@ dependencies = [
[[package]]
name = "rustpython-literal"
version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=4d03b9b5b212fc869e4cfda151414438186a7779#4d03b9b5b212fc869e4cfda151414438186a7779"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72#5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72"
dependencies = [
"hexf-parse",
"is-macro",
@ -2347,7 +2347,7 @@ dependencies = [
[[package]]
name = "rustpython-parser"
version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=4d03b9b5b212fc869e4cfda151414438186a7779#4d03b9b5b212fc869e4cfda151414438186a7779"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72#5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72"
dependencies = [
"anyhow",
"is-macro",
@ -2370,7 +2370,7 @@ dependencies = [
[[package]]
name = "rustpython-parser-core"
version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=4d03b9b5b212fc869e4cfda151414438186a7779#4d03b9b5b212fc869e4cfda151414438186a7779"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72#5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72"
dependencies = [
"is-macro",
"memchr",

View file

@ -51,11 +51,11 @@ wsl = { version = "0.1.0" }
# v1.0.1
libcst = { git = "https://github.com/Instagram/LibCST.git", rev = "3cacca1a1029f05707e50703b49fe3dd860aa839", default-features = false }
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "4d03b9b5b212fc869e4cfda151414438186a7779" }
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "4d03b9b5b212fc869e4cfda151414438186a7779" , default-features = false, features = ["num-bigint"]}
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "4d03b9b5b212fc869e4cfda151414438186a7779", default-features = false, features = ["num-bigint"] }
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "4d03b9b5b212fc869e4cfda151414438186a7779", default-features = false }
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "4d03b9b5b212fc869e4cfda151414438186a7779" , default-features = false, features = ["full-lexer", "num-bigint"] }
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72" }
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72" , default-features = false, features = ["num-bigint"]}
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72", default-features = false, features = ["num-bigint"] }
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72", default-features = false }
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72" , default-features = false, features = ["full-lexer", "num-bigint"] }
[profile.release]
lto = "fat"

View file

@ -671,11 +671,13 @@ impl<'stmt> BasicBlocksBuilder<'stmt> {
| Expr::Await(_)
| Expr::Yield(_)
| Expr::YieldFrom(_) => self.unconditional_next_block(after),
Expr::LineMagic(_) => todo!(),
}
}
// The tough branches are done, here is an easy one.
Stmt::Return(_) => NextBlock::Terminate,
Stmt::TypeAlias(_) => todo!(),
Stmt::LineMagic(_) => todo!(),
};
// Include any statements in the block that don't divert the control flow.
@ -922,6 +924,7 @@ fn needs_next_block(stmts: &[Stmt]) -> bool {
| Stmt::TryStar(_)
| Stmt::Assert(_) => true,
Stmt::TypeAlias(_) => todo!(),
Stmt::LineMagic(_) => todo!(),
}
}
@ -957,6 +960,7 @@ fn is_control_flow_stmt(stmt: &Stmt) -> bool {
| Stmt::Break(_)
| Stmt::Continue(_) => true,
Stmt::TypeAlias(_) => todo!(),
Stmt::LineMagic(_) => todo!(),
}
}

View file

@ -652,6 +652,12 @@ pub struct ExprSlice<'a> {
step: Option<Box<ComparableExpr<'a>>>,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprLineMagic<'a> {
kind: ast::MagicKind,
value: &'a str,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableExpr<'a> {
BoolOp(ExprBoolOp<'a>),
@ -681,6 +687,7 @@ pub enum ComparableExpr<'a> {
List(ExprList<'a>),
Tuple(ExprTuple<'a>),
Slice(ExprSlice<'a>),
LineMagic(ExprLineMagic<'a>),
}
impl<'a> From<&'a Box<ast::Expr>> for Box<ComparableExpr<'a>> {
@ -925,6 +932,14 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
upper: upper.as_ref().map(Into::into),
step: step.as_ref().map(Into::into),
}),
ast::Expr::LineMagic(ast::ExprLineMagic {
kind,
value,
range: _range,
}) => Self::LineMagic(ExprLineMagic {
kind: *kind,
value: value.as_str(),
}),
}
}
}
@ -1155,6 +1170,12 @@ pub struct StmtExpr<'a> {
value: ComparableExpr<'a>,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct StmtLineMagic<'a> {
kind: ast::MagicKind,
value: &'a str,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableStmt<'a> {
FunctionDef(StmtFunctionDef<'a>),
@ -1181,6 +1202,7 @@ pub enum ComparableStmt<'a> {
ImportFrom(StmtImportFrom<'a>),
Global(StmtGlobal<'a>),
Nonlocal(StmtNonlocal<'a>),
LineMagic(StmtLineMagic<'a>),
Expr(StmtExpr<'a>),
Pass,
Break,
@ -1440,6 +1462,14 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
}) => Self::Nonlocal(StmtNonlocal {
names: names.iter().map(ast::Identifier::as_str).collect(),
}),
ast::Stmt::LineMagic(ast::StmtLineMagic {
kind,
value,
range: _range,
}) => Self::LineMagic(StmtLineMagic {
kind: *kind,
value: value.as_str(),
}),
ast::Stmt::Expr(ast::StmtExpr {
value,
range: _range,

View file

@ -281,6 +281,7 @@ where
.map_or(false, |value| any_over_expr(value, func))
}
Expr::Name(_) | Expr::Constant(_) => false,
Expr::LineMagic(_) => false,
}
}
@ -583,6 +584,7 @@ where
range: _range,
}) => any_over_expr(value, func),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) => false,
Stmt::LineMagic(_) => false,
}
}

View file

@ -54,6 +54,7 @@ pub enum AnyNode {
StmtPass(ast::StmtPass),
StmtBreak(ast::StmtBreak),
StmtContinue(ast::StmtContinue),
StmtLineMagic(ast::StmtLineMagic),
ExprBoolOp(ast::ExprBoolOp),
ExprNamedExpr(ast::ExprNamedExpr),
ExprBinOp(ast::ExprBinOp),
@ -81,6 +82,7 @@ pub enum AnyNode {
ExprList(ast::ExprList),
ExprTuple(ast::ExprTuple),
ExprSlice(ast::ExprSlice),
ExprLineMagic(ast::ExprLineMagic),
ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler),
PatternMatchValue(ast::PatternMatchValue),
PatternMatchSingleton(ast::PatternMatchSingleton),
@ -137,6 +139,7 @@ impl AnyNode {
AnyNode::StmtPass(node) => Some(Stmt::Pass(node)),
AnyNode::StmtBreak(node) => Some(Stmt::Break(node)),
AnyNode::StmtContinue(node) => Some(Stmt::Continue(node)),
AnyNode::StmtLineMagic(node) => Some(Stmt::LineMagic(node)),
AnyNode::ModModule(_)
| AnyNode::ModInteractive(_)
@ -169,6 +172,7 @@ impl AnyNode {
| AnyNode::ExprList(_)
| AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_)
| AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_)
@ -224,6 +228,7 @@ impl AnyNode {
AnyNode::ExprList(node) => Some(Expr::List(node)),
AnyNode::ExprTuple(node) => Some(Expr::Tuple(node)),
AnyNode::ExprSlice(node) => Some(Expr::Slice(node)),
AnyNode::ExprLineMagic(node) => Some(Expr::LineMagic(node)),
AnyNode::ModModule(_)
| AnyNode::ModInteractive(_)
@ -257,6 +262,7 @@ impl AnyNode {
| AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_)
| AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_)
@ -318,6 +324,7 @@ impl AnyNode {
| AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_)
| AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_)
@ -345,6 +352,7 @@ impl AnyNode {
| AnyNode::ExprList(_)
| AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_)
| AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_)
@ -414,6 +422,7 @@ impl AnyNode {
| AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_)
| AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_)
@ -441,6 +450,7 @@ impl AnyNode {
| AnyNode::ExprList(_)
| AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_)
| AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::TypeIgnoreTypeIgnore(_)
| AnyNode::Comprehension(_)
@ -495,6 +505,7 @@ impl AnyNode {
| AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_)
| AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_)
@ -522,6 +533,7 @@ impl AnyNode {
| AnyNode::ExprList(_)
| AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_)
| AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_)
| AnyNode::PatternMatchSequence(_)
@ -583,6 +595,7 @@ impl AnyNode {
| AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_)
| AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_)
@ -610,6 +623,7 @@ impl AnyNode {
| AnyNode::ExprList(_)
| AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_)
| AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_)
| AnyNode::PatternMatchSequence(_)
@ -693,6 +707,7 @@ impl AnyNode {
Self::StmtPass(node) => AnyNodeRef::StmtPass(node),
Self::StmtBreak(node) => AnyNodeRef::StmtBreak(node),
Self::StmtContinue(node) => AnyNodeRef::StmtContinue(node),
Self::StmtLineMagic(node) => AnyNodeRef::StmtLineMagic(node),
Self::ExprBoolOp(node) => AnyNodeRef::ExprBoolOp(node),
Self::ExprNamedExpr(node) => AnyNodeRef::ExprNamedExpr(node),
Self::ExprBinOp(node) => AnyNodeRef::ExprBinOp(node),
@ -720,6 +735,7 @@ impl AnyNode {
Self::ExprList(node) => AnyNodeRef::ExprList(node),
Self::ExprTuple(node) => AnyNodeRef::ExprTuple(node),
Self::ExprSlice(node) => AnyNodeRef::ExprSlice(node),
Self::ExprLineMagic(node) => AnyNodeRef::ExprLineMagic(node),
Self::ExceptHandlerExceptHandler(node) => AnyNodeRef::ExceptHandlerExceptHandler(node),
Self::PatternMatchValue(node) => AnyNodeRef::PatternMatchValue(node),
Self::PatternMatchSingleton(node) => AnyNodeRef::PatternMatchSingleton(node),
@ -1676,6 +1692,34 @@ impl AstNode for ast::StmtContinue {
AnyNode::from(self)
}
}
impl AstNode for ast::StmtLineMagic {
fn cast(kind: AnyNode) -> Option<Self>
where
Self: Sized,
{
if let AnyNode::StmtLineMagic(node) = kind {
Some(node)
} else {
None
}
}
fn cast_ref(kind: AnyNodeRef) -> Option<&Self> {
if let AnyNodeRef::StmtLineMagic(node) = kind {
Some(node)
} else {
None
}
}
fn as_any_node_ref(&self) -> AnyNodeRef {
AnyNodeRef::from(self)
}
fn into_any_node(self) -> AnyNode {
AnyNode::from(self)
}
}
impl AstNode for ast::ExprBoolOp {
fn cast(kind: AnyNode) -> Option<Self>
where
@ -2432,6 +2476,34 @@ impl AstNode for ast::ExprSlice {
AnyNode::from(self)
}
}
impl AstNode for ast::ExprLineMagic {
fn cast(kind: AnyNode) -> Option<Self>
where
Self: Sized,
{
if let AnyNode::ExprLineMagic(node) = kind {
Some(node)
} else {
None
}
}
fn cast_ref(kind: AnyNodeRef) -> Option<&Self> {
if let AnyNodeRef::ExprLineMagic(node) = kind {
Some(node)
} else {
None
}
}
fn as_any_node_ref(&self) -> AnyNodeRef {
AnyNodeRef::from(self)
}
fn into_any_node(self) -> AnyNode {
AnyNode::from(self)
}
}
impl AstNode for ast::ExceptHandlerExceptHandler {
fn cast(kind: AnyNode) -> Option<Self>
where
@ -3081,6 +3153,7 @@ impl From<Stmt> for AnyNode {
Stmt::Pass(node) => AnyNode::StmtPass(node),
Stmt::Break(node) => AnyNode::StmtBreak(node),
Stmt::Continue(node) => AnyNode::StmtContinue(node),
Stmt::LineMagic(node) => AnyNode::StmtLineMagic(node),
}
}
}
@ -3115,6 +3188,7 @@ impl From<Expr> for AnyNode {
Expr::List(node) => AnyNode::ExprList(node),
Expr::Tuple(node) => AnyNode::ExprTuple(node),
Expr::Slice(node) => AnyNode::ExprSlice(node),
Expr::LineMagic(node) => AnyNode::ExprLineMagic(node),
}
}
}
@ -3359,6 +3433,12 @@ impl From<ast::StmtContinue> for AnyNode {
}
}
impl From<ast::StmtLineMagic> for AnyNode {
fn from(node: ast::StmtLineMagic) -> Self {
AnyNode::StmtLineMagic(node)
}
}
impl From<ast::ExprBoolOp> for AnyNode {
fn from(node: ast::ExprBoolOp) -> Self {
AnyNode::ExprBoolOp(node)
@ -3521,6 +3601,12 @@ impl From<ast::ExprSlice> for AnyNode {
}
}
impl From<ast::ExprLineMagic> for AnyNode {
fn from(node: ast::ExprLineMagic) -> Self {
AnyNode::ExprLineMagic(node)
}
}
impl From<ast::ExceptHandlerExceptHandler> for AnyNode {
fn from(node: ast::ExceptHandlerExceptHandler) -> Self {
AnyNode::ExceptHandlerExceptHandler(node)
@ -3679,6 +3765,7 @@ impl Ranged for AnyNode {
AnyNode::StmtPass(node) => node.range(),
AnyNode::StmtBreak(node) => node.range(),
AnyNode::StmtContinue(node) => node.range(),
AnyNode::StmtLineMagic(node) => node.range(),
AnyNode::ExprBoolOp(node) => node.range(),
AnyNode::ExprNamedExpr(node) => node.range(),
AnyNode::ExprBinOp(node) => node.range(),
@ -3706,6 +3793,7 @@ impl Ranged for AnyNode {
AnyNode::ExprList(node) => node.range(),
AnyNode::ExprTuple(node) => node.range(),
AnyNode::ExprSlice(node) => node.range(),
AnyNode::ExprLineMagic(node) => node.range(),
AnyNode::ExceptHandlerExceptHandler(node) => node.range(),
AnyNode::PatternMatchValue(node) => node.range(),
AnyNode::PatternMatchSingleton(node) => node.range(),
@ -3767,6 +3855,7 @@ pub enum AnyNodeRef<'a> {
StmtPass(&'a ast::StmtPass),
StmtBreak(&'a ast::StmtBreak),
StmtContinue(&'a ast::StmtContinue),
StmtLineMagic(&'a ast::StmtLineMagic),
ExprBoolOp(&'a ast::ExprBoolOp),
ExprNamedExpr(&'a ast::ExprNamedExpr),
ExprBinOp(&'a ast::ExprBinOp),
@ -3794,6 +3883,7 @@ pub enum AnyNodeRef<'a> {
ExprList(&'a ast::ExprList),
ExprTuple(&'a ast::ExprTuple),
ExprSlice(&'a ast::ExprSlice),
ExprLineMagic(&'a ast::ExprLineMagic),
ExceptHandlerExceptHandler(&'a ast::ExceptHandlerExceptHandler),
PatternMatchValue(&'a ast::PatternMatchValue),
PatternMatchSingleton(&'a ast::PatternMatchSingleton),
@ -3854,6 +3944,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::StmtPass(node) => NonNull::from(*node).cast(),
AnyNodeRef::StmtBreak(node) => NonNull::from(*node).cast(),
AnyNodeRef::StmtContinue(node) => NonNull::from(*node).cast(),
AnyNodeRef::StmtLineMagic(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprBoolOp(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprNamedExpr(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprBinOp(node) => NonNull::from(*node).cast(),
@ -3881,6 +3972,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::ExprList(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprTuple(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprSlice(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprLineMagic(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExceptHandlerExceptHandler(node) => NonNull::from(*node).cast(),
AnyNodeRef::PatternMatchValue(node) => NonNull::from(*node).cast(),
AnyNodeRef::PatternMatchSingleton(node) => NonNull::from(*node).cast(),
@ -3947,6 +4039,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::StmtPass(_) => NodeKind::StmtPass,
AnyNodeRef::StmtBreak(_) => NodeKind::StmtBreak,
AnyNodeRef::StmtContinue(_) => NodeKind::StmtContinue,
AnyNodeRef::StmtLineMagic(_) => NodeKind::StmtLineMagic,
AnyNodeRef::ExprBoolOp(_) => NodeKind::ExprBoolOp,
AnyNodeRef::ExprNamedExpr(_) => NodeKind::ExprNamedExpr,
AnyNodeRef::ExprBinOp(_) => NodeKind::ExprBinOp,
@ -3974,6 +4067,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::ExprList(_) => NodeKind::ExprList,
AnyNodeRef::ExprTuple(_) => NodeKind::ExprTuple,
AnyNodeRef::ExprSlice(_) => NodeKind::ExprSlice,
AnyNodeRef::ExprLineMagic(_) => NodeKind::ExprLineMagic,
AnyNodeRef::ExceptHandlerExceptHandler(_) => NodeKind::ExceptHandlerExceptHandler,
AnyNodeRef::PatternMatchValue(_) => NodeKind::PatternMatchValue,
AnyNodeRef::PatternMatchSingleton(_) => NodeKind::PatternMatchSingleton,
@ -4029,7 +4123,8 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtExpr(_)
| AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_) => true,
| AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_) => true,
AnyNodeRef::ModModule(_)
| AnyNodeRef::ModInteractive(_)
@ -4062,6 +4157,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_)
@ -4116,7 +4212,8 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprName(_)
| AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_) => true,
| AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_) => true,
AnyNodeRef::ModModule(_)
| AnyNodeRef::ModInteractive(_)
@ -4150,6 +4247,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_)
@ -4211,6 +4309,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_)
| AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_)
@ -4238,6 +4337,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_)
@ -4307,6 +4407,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_)
| AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_)
@ -4334,6 +4435,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::TypeIgnoreTypeIgnore(_)
| AnyNodeRef::Comprehension(_)
@ -4388,6 +4490,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_)
| AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_)
@ -4415,6 +4518,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_)
| AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_)
| AnyNodeRef::PatternMatchSequence(_)
@ -4476,6 +4580,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_)
| AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_)
@ -4503,6 +4608,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_)
| AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_)
| AnyNodeRef::PatternMatchSequence(_)
@ -4755,6 +4861,12 @@ impl<'a> From<&'a ast::StmtContinue> for AnyNodeRef<'a> {
}
}
impl<'a> From<&'a ast::StmtLineMagic> for AnyNodeRef<'a> {
fn from(node: &'a ast::StmtLineMagic) -> Self {
AnyNodeRef::StmtLineMagic(node)
}
}
impl<'a> From<&'a ast::ExprBoolOp> for AnyNodeRef<'a> {
fn from(node: &'a ast::ExprBoolOp) -> Self {
AnyNodeRef::ExprBoolOp(node)
@ -4917,6 +5029,12 @@ impl<'a> From<&'a ast::ExprSlice> for AnyNodeRef<'a> {
}
}
impl<'a> From<&'a ast::ExprLineMagic> for AnyNodeRef<'a> {
fn from(node: &'a ast::ExprLineMagic) -> Self {
AnyNodeRef::ExprLineMagic(node)
}
}
impl<'a> From<&'a ast::ExceptHandlerExceptHandler> for AnyNodeRef<'a> {
fn from(node: &'a ast::ExceptHandlerExceptHandler) -> Self {
AnyNodeRef::ExceptHandlerExceptHandler(node)
@ -5032,6 +5150,7 @@ impl<'a> From<&'a Stmt> for AnyNodeRef<'a> {
Stmt::Pass(node) => AnyNodeRef::StmtPass(node),
Stmt::Break(node) => AnyNodeRef::StmtBreak(node),
Stmt::Continue(node) => AnyNodeRef::StmtContinue(node),
Stmt::LineMagic(node) => AnyNodeRef::StmtLineMagic(node),
}
}
}
@ -5066,6 +5185,7 @@ impl<'a> From<&'a Expr> for AnyNodeRef<'a> {
Expr::List(node) => AnyNodeRef::ExprList(node),
Expr::Tuple(node) => AnyNodeRef::ExprTuple(node),
Expr::Slice(node) => AnyNodeRef::ExprSlice(node),
Expr::LineMagic(node) => AnyNodeRef::ExprLineMagic(node),
}
}
}
@ -5200,6 +5320,7 @@ impl Ranged for AnyNodeRef<'_> {
AnyNodeRef::StmtPass(node) => node.range(),
AnyNodeRef::StmtBreak(node) => node.range(),
AnyNodeRef::StmtContinue(node) => node.range(),
AnyNodeRef::StmtLineMagic(node) => node.range(),
AnyNodeRef::ExprBoolOp(node) => node.range(),
AnyNodeRef::ExprNamedExpr(node) => node.range(),
AnyNodeRef::ExprBinOp(node) => node.range(),
@ -5227,6 +5348,7 @@ impl Ranged for AnyNodeRef<'_> {
AnyNodeRef::ExprList(node) => node.range(),
AnyNodeRef::ExprTuple(node) => node.range(),
AnyNodeRef::ExprSlice(node) => node.range(),
AnyNodeRef::ExprLineMagic(node) => node.range(),
AnyNodeRef::ExceptHandlerExceptHandler(node) => node.range(),
AnyNodeRef::PatternMatchValue(node) => node.range(),
AnyNodeRef::PatternMatchSingleton(node) => node.range(),
@ -5284,6 +5406,7 @@ pub enum NodeKind {
StmtImportFrom,
StmtGlobal,
StmtNonlocal,
StmtLineMagic,
StmtExpr,
StmtPass,
StmtBreak,
@ -5315,6 +5438,7 @@ pub enum NodeKind {
ExprList,
ExprTuple,
ExprSlice,
ExprLineMagic,
ExceptHandlerExceptHandler,
PatternMatchValue,
PatternMatchSingleton,

View file

@ -200,5 +200,8 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) {
relocate_expr(expr, location);
}
}
Expr::LineMagic(ast::ExprLineMagic { range, .. }) => {
*range = location;
}
}
}

View file

@ -720,6 +720,11 @@ impl<'a> Generator<'a> {
self.p("continue");
});
}
Stmt::LineMagic(ast::StmtLineMagic { kind, value, .. }) => {
statement!({
self.p(&format!("{kind}{value}"));
});
}
}
}
@ -1270,6 +1275,9 @@ impl<'a> Generator<'a> {
self.unparse_expr(step, precedence::SLICE);
}
}
Expr::LineMagic(ast::ExprLineMagic { kind, value, .. }) => {
self.p(&format!("{kind}{value}"));
}
}
}
@ -1467,8 +1475,8 @@ impl<'a> Generator<'a> {
#[cfg(test)]
mod tests {
use rustpython_ast::Stmt;
use rustpython_parser::Parse;
use rustpython_ast::{Mod, ModModule, Stmt};
use rustpython_parser::{self, Mode, Parse};
use ruff_python_trivia::LineEnding;
@ -1497,6 +1505,22 @@ mod tests {
generator.generate()
}
fn jupyter_round_trip(contents: &str) -> String {
let indentation = Indentation::default();
let quote = Quote::default();
let line_ending = LineEnding::default();
let ast = rustpython_parser::parse(contents, Mode::Jupyter, "<filename>").unwrap();
let Mod::Module(ModModule { body, .. }) = ast else {
panic!("Source code didn't return ModModule")
};
let [stmt] = body.as_slice() else {
panic!("Expected only one statement in source code")
};
let mut generator = Generator::new(&indentation, quote, line_ending);
generator.unparse_stmt(stmt);
generator.generate()
}
macro_rules! assert_round_trip {
($contents:expr) => {
assert_eq!(
@ -1506,6 +1530,19 @@ mod tests {
};
}
#[test]
fn unparse_magic_commands() {
assert_eq!(
jupyter_round_trip("%matplotlib inline"),
"%matplotlib inline"
);
assert_eq!(
jupyter_round_trip("%matplotlib \\\n inline"),
"%matplotlib inline"
);
assert_eq!(jupyter_round_trip("dir = !pwd"), "dir = !pwd");
}
#[test]
fn unparse() {
assert_round_trip!("{i for i in b async for i in a if await i for b in i}");

View file

@ -12,6 +12,8 @@ pub enum TokenKind {
Complex,
/// Token value for a string.
String,
/// Token value for a Jupyter magic command.
MagicCommand,
/// Token value for a comment. These are filtered out of the token stream prior to parsing.
Comment,
/// Token value for a newline.
@ -339,6 +341,7 @@ impl TokenKind {
Tok::Float { .. } => TokenKind::Float,
Tok::Complex { .. } => TokenKind::Complex,
Tok::String { .. } => TokenKind::String,
Tok::MagicCommand { .. } => TokenKind::MagicCommand,
Tok::Comment(_) => TokenKind::Comment,
Tok::Newline => TokenKind::Newline,
Tok::NonLogicalNewline => TokenKind::NonLogicalNewline,
@ -433,7 +436,6 @@ impl TokenKind {
Tok::StartModule => TokenKind::StartModule,
Tok::StartInteractive => TokenKind::StartInteractive,
Tok::StartExpression => TokenKind::StartExpression,
Tok::MagicCommand { .. } => todo!(),
}
}
}

View file

@ -361,7 +361,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
value,
range: _range,
}) => visitor.visit_expr(value),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) => {}
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) | Stmt::LineMagic(_) => {}
}
}
@ -613,6 +613,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
visitor.visit_expr(expr);
}
}
Expr::LineMagic(_) => {}
}
}

View file

@ -428,7 +428,8 @@ where
| Stmt::Break(_)
| Stmt::Continue(_)
| Stmt::Global(_)
| Stmt::Nonlocal(_) => {}
| Stmt::Nonlocal(_)
| Stmt::LineMagic(_) => {}
}
}
@ -723,6 +724,7 @@ where
visitor.visit_expr(expr);
}
}
Expr::LineMagic(_) => (),
}
}

View file

@ -92,6 +92,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
Expr::List(expr) => expr.format().fmt(f),
Expr::Tuple(expr) => expr.format().fmt(f),
Expr::Slice(expr) => expr.format().fmt(f),
Expr::LineMagic(_) => todo!(),
});
let parenthesize = match parentheses {
@ -233,6 +234,7 @@ impl NeedsParentheses for Expr {
Expr::List(expr) => expr.needs_parentheses(parent, context),
Expr::Tuple(expr) => expr.needs_parentheses(parent, context),
Expr::Slice(expr) => expr.needs_parentheses(parent, context),
Expr::LineMagic(_) => todo!(),
}
}
}
@ -405,6 +407,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
| Expr::Starred(_)
| Expr::Name(_)
| Expr::Slice(_) => {}
Expr::LineMagic(_) => todo!(),
};
walk_expr(self, expr);

View file

@ -66,6 +66,7 @@ impl FormatRule<Stmt, PyFormatContext<'_>> for FormatStmt {
Stmt::Break(x) => x.format().fmt(f),
Stmt::Continue(x) => x.format().fmt(f),
Stmt::TypeAlias(x) => x.format().fmt(f),
Stmt::LineMagic(_) => todo!(),
}
}
}

View file

@ -24,7 +24,7 @@ ruff_python_ast = { path = "../crates/ruff_python_ast" }
ruff_python_formatter = { path = "../crates/ruff_python_formatter" }
similar = { version = "2.2.1" }
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "4d03b9b5b212fc869e4cfda151414438186a7779" , default-features = false, features = ["full-lexer", "num-bigint"] }
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "5ef4ccd6322a8b7c5e8ead0ae3c89426d7be7d72" , default-features = false, features = ["full-lexer", "num-bigint"] }
# Prevent this from interfering with workspaces
[workspace]