Formatter parentheses support for IpyEscapeCommand (#8207)

## Summary

This PR removes the `todo!()` around `IpyEscapeCommand` in the
formatter.

The `NeedsParentheses` trait needs to be implemented which always return
`Never`. The reason being that if an escape command is parenthesized,
then that's not parsed as an escape command. IOW, the parentheses
shouldn't be present around an escape command.

In the similar way, the `CanSkipOptionalParenthesesVisitor` will skip
this node.

## Test Plan

Updated the `unformatted.ipynb` fixture with new cells containing
IPython escape commands and the corresponding snapshot was verified.
Also, tested it out in a few open source repositories containing
notebooks (`openai/openai-cookbook`, `huggingface/notebooks`).

#### New cells in `unformatted.ipynb`

**Cell 2**
```markdown
A markdown cell
```

**Cell 3**
```python
def some_function(foo, bar):
    pass
%matplotlib inline
```

**Cell 4**
```python
foo = %pwd
def some_function(foo,bar,):
	foo = %pwd
    print(foo
	)
```

fixes: #8204
This commit is contained in:
Dhruv Manilawala 2023-10-25 19:31:50 +05:30 committed by GitHub
parent c2ec5f0bc9
commit dbd84c947b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 4 deletions

View file

@ -1,6 +1,7 @@
use ruff_python_ast::ExprIpyEscapeCommand;
use ruff_text_size::Ranged;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
#[derive(Default)]
@ -11,3 +12,13 @@ impl FormatNodeRule<ExprIpyEscapeCommand> for FormatExprIpyEscapeCommand {
source_text_slice(item.range()).fmt(f)
}
}
impl NeedsParentheses for ExprIpyEscapeCommand {
fn needs_parentheses(
&self,
_parent: ruff_python_ast::AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -476,7 +476,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::IpyEscapeCommand(_) => todo!(),
Expr::IpyEscapeCommand(expr) => expr.needs_parentheses(parent, context),
}
}
}
@ -718,8 +718,8 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
| Expr::Constant(_)
| Expr::Starred(_)
| Expr::Name(_)
| Expr::Slice(_) => {}
Expr::IpyEscapeCommand(_) => todo!(),
| Expr::Slice(_)
| Expr::IpyEscapeCommand(_) => {}
};
walk_expr(self, expr);