Use Display for formatter parse errors (#9316)

## Summary

This helps a bit with (but does not close) the issues described in
https://github.com/astral-sh/ruff/issues/9311. E.g., now, we at least
see: `error: Failed to format main.py: source contains syntax errors:
invalid syntax. Got unexpected token '=' at byte offset 20`.
This commit is contained in:
Charlie Marsh 2023-12-29 18:26:57 -04:00 committed by GitHub
parent 2895e7d126
commit 97e9d3c54f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 8 deletions

View file

@ -408,11 +408,13 @@ pub(crate) fn format_source(
pub(crate) enum FormatResult { pub(crate) enum FormatResult {
/// The file was formatted. /// The file was formatted.
Formatted, Formatted,
/// The file was formatted, [`SourceKind`] contains the formatted code /// The file was formatted, [`SourceKind`] contains the formatted code
Diff { Diff {
unformatted: SourceKind, unformatted: SourceKind,
formatted: SourceKind, formatted: SourceKind,
}, },
/// The file was unchanged, as the formatted contents matched the existing contents. /// The file was unchanged, as the formatted contents matched the existing contents.
Unchanged, Unchanged,

View file

@ -328,6 +328,32 @@ OTHER = "OTHER"
Ok(()) Ok(())
} }
#[test]
fn syntax_error() -> Result<()> {
let tempdir = TempDir::new()?;
fs::write(
tempdir.path().join("main.py"),
r#"
from module import =
"#,
)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.args(["format", "--no-cache", "--isolated", "--check"])
.arg("main.py"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to format main.py: source contains syntax errors: invalid syntax. Got unexpected token '=' at byte offset 20
"###);
Ok(())
}
#[test] #[test]
fn messages() -> Result<()> { fn messages() -> Result<()> {
let tempdir = TempDir::new()?; let tempdir = TempDir::new()?;

View file

@ -108,9 +108,9 @@ where
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum FormatModuleError { pub enum FormatModuleError {
#[error("source contains syntax errors: {0:?}")] #[error("source contains syntax errors: {0}")]
LexError(LexicalError), LexError(LexicalError),
#[error("source contains syntax errors: {0:?}")] #[error("source contains syntax errors: {0}")]
ParseError(ParseError), ParseError(ParseError),
#[error(transparent)] #[error(transparent)]
FormatError(#[from] FormatError), FormatError(#[from] FormatError),

View file

@ -1308,6 +1308,31 @@ impl LexicalError {
} }
} }
impl std::ops::Deref for LexicalError {
type Target = LexicalErrorType;
fn deref(&self) -> &Self::Target {
&self.error
}
}
impl std::error::Error for LexicalError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
impl std::fmt::Display for LexicalError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{} at byte offset {}",
&self.error,
u32::from(self.location)
)
}
}
/// Represents the different types of errors that can occur during lexing. /// Represents the different types of errors that can occur during lexing.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum LexicalErrorType { pub enum LexicalErrorType {
@ -1350,6 +1375,8 @@ pub enum LexicalErrorType {
OtherError(String), OtherError(String),
} }
impl std::error::Error for LexicalErrorType {}
impl std::fmt::Display for LexicalErrorType { impl std::fmt::Display for LexicalErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {

View file

@ -305,12 +305,6 @@ impl fmt::Display for ParseError {
} }
} }
impl ParseError {
pub fn error(self) -> ParseErrorType {
self.error
}
}
/// Represents the different types of errors that can occur during parsing. /// Represents the different types of errors that can occur during parsing.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum ParseErrorType { pub enum ParseErrorType {