Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add most formatter options to ruff.toml / pyproject.toml #7566

Merged
merged 1 commit into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

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

34 changes: 16 additions & 18 deletions crates/ruff_cli/src/commands/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use ruff_linter::fs;
use ruff_linter::logging::LogLevel;
use ruff_linter::warn_user_once;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions};
use ruff_source_file::{find_newline, LineEnding};
use ruff_python_formatter::{format_module, FormatModuleError};
use ruff_workspace::resolver::python_files_in_path;
use ruff_workspace::FormatterSettings;

use crate::args::{CliOverrides, FormatArguments};
use crate::panic::{catch_unwind, PanicError};
Expand Down Expand Up @@ -73,15 +73,17 @@ pub(crate) fn format(
};

let resolved_settings = resolver.resolve(path, &pyproject_config);
let options = resolved_settings.formatter.to_format_options(source_type);
debug!("Formatting {} with {:?}", path.display(), options);

Some(match catch_unwind(|| format_path(path, options, mode)) {
Ok(inner) => inner,
Err(error) => {
Err(FormatCommandError::Panic(Some(path.to_path_buf()), error))
}
})
Some(
match catch_unwind(|| {
format_path(path, &resolved_settings.formatter, source_type, mode)
}) {
Ok(inner) => inner,
Err(error) => {
Err(FormatCommandError::Panic(Some(path.to_path_buf()), error))
}
},
)
}
Err(err) => Some(Err(FormatCommandError::Ignore(err))),
}
Expand Down Expand Up @@ -139,19 +141,15 @@ pub(crate) fn format(
#[tracing::instrument(skip_all, fields(path = %path.display()))]
fn format_path(
path: &Path,
options: PyFormatOptions,
settings: &FormatterSettings,
source_type: PySourceType,
mode: FormatMode,
) -> Result<FormatCommandResult, FormatCommandError> {
let unformatted = std::fs::read_to_string(path)
.map_err(|err| FormatCommandError::Read(Some(path.to_path_buf()), err))?;

let line_ending = match find_newline(&unformatted) {
Some((_, LineEnding::Lf)) | None => ruff_formatter::printer::LineEnding::LineFeed,
Some((_, LineEnding::Cr)) => ruff_formatter::printer::LineEnding::CarriageReturn,
Some((_, LineEnding::CrLf)) => ruff_formatter::printer::LineEnding::CarriageReturnLineFeed,
};

let options = options.with_line_ending(line_ending);
let options = settings.to_format_options(source_type, &unformatted);
debug!("Formatting {} with {:?}", path.display(), options);

let formatted = format_module(&unformatted, options)
.map_err(|err| FormatCommandError::FormatModule(Some(path.to_path_buf()), err))?;
Expand Down
18 changes: 10 additions & 8 deletions crates/ruff_cli/src/commands/format_stdin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use anyhow::Result;
use log::warn;

use ruff_python_ast::PySourceType;
use ruff_python_formatter::{format_module, PyFormatOptions};
use ruff_python_formatter::format_module;
use ruff_workspace::resolver::python_file_at_path;
use ruff_workspace::FormatterSettings;

use crate::args::{CliOverrides, FormatArguments};
use crate::commands::format::{FormatCommandError, FormatCommandResult, FormatMode};
Expand Down Expand Up @@ -37,12 +38,7 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
// Format the file.
let path = cli.stdin_filename.as_deref();

let options = pyproject_config
.settings
.formatter
.to_format_options(path.map(PySourceType::from).unwrap_or_default());

match format_source(path, options, mode) {
match format_source(path, &pyproject_config.settings.formatter, mode) {
Ok(result) => match mode {
FormatMode::Write => Ok(ExitStatus::Success),
FormatMode::Check => {
Expand All @@ -63,11 +59,17 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
/// Format source code read from `stdin`.
fn format_source(
path: Option<&Path>,
options: PyFormatOptions,
settings: &FormatterSettings,
mode: FormatMode,
) -> Result<FormatCommandResult, FormatCommandError> {
let unformatted = read_from_stdin()
.map_err(|err| FormatCommandError::Read(path.map(Path::to_path_buf), err))?;

let options = settings.to_format_options(
path.map(PySourceType::from).unwrap_or_default(),
&unformatted,
);

let formatted = format_module(&unformatted, options)
.map_err(|err| FormatCommandError::FormatModule(path.map(Path::to_path_buf), err))?;
let formatted = formatted.as_code();
Expand Down
207 changes: 207 additions & 0 deletions crates/ruff_cli/tests/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#![cfg(not(target_family = "wasm"))]

use std::fs;
use std::process::Command;
use std::str;

use anyhow::Result;
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
use tempfile::TempDir;

const BIN_NAME: &str = "ruff";

#[test]
fn default_options() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["format", "--isolated"])
.arg("-")
.pass_stdin(r#"
def foo(arg1, arg2,):
print('Should\'t change quotes')


if condition:

print('Hy "Micha"') # Should not change quotes

"#), @r###"
success: true
exit_code: 0
----- stdout -----
def foo(
arg1,
arg2,
):
print("Should't change quotes")


if condition:
print('Hy "Micha"') # Should not change quotes

----- stderr -----
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended only for experimentation.
"###);
}

#[test]
fn format_options() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
[format]
indent-style = "tab"
quote-style = "single"
skip-magic-trailing-comma = true
line-ending = "cr-lf"
"#,
)?;

assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["format", "--config"])
.arg(&ruff_toml)
.arg("-")
.pass_stdin(r#"
def foo(arg1, arg2,):
print("Shouldn't change quotes")


if condition:

print("Should change quotes")

"#), @r###"
success: true
exit_code: 0
----- stdout -----
def foo(arg1, arg2):
print("Shouldn't change quotes")


if condition:
print('Should change quotes')

----- stderr -----
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended only for experimentation.
"###);
Ok(())
}

#[test]
fn format_option_inheritance() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
let base_toml = tempdir.path().join("base.toml");
fs::write(
&ruff_toml,
r#"
extend = "base.toml"

[format]
quote-style = "single"
"#,
)?;

fs::write(
base_toml,
r#"
[format]
indent-style = "tab"
"#,
)?;

assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["format", "--config"])
.arg(&ruff_toml)
.arg("-")
.pass_stdin(r#"
def foo(arg1, arg2,):
print("Shouldn't change quotes")


if condition:

print("Should change quotes")

"#), @r###"
success: true
exit_code: 0
----- stdout -----
def foo(
arg1,
arg2,
):
print("Shouldn't change quotes")


if condition:
print('Should change quotes')

----- stderr -----
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended only for experimentation.
"###);
Ok(())
}

/// Tests that the legacy `format` option continues to work but emits a warning.
#[test]
fn legacy_format_option() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
format = "json"
"#,
)?;

assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["check", "--select", "F401", "--no-cache", "--config"])
.arg(&ruff_toml)
.arg("-")
.pass_stdin(r#"
import os
"#), @r###"
success: false
exit_code: 1
----- stdout -----
[
{
"code": "F401",
"end_location": {
"column": 10,
"row": 2
},
"filename": "-",
"fix": {
"applicability": "Automatic",
"edits": [
{
"content": "",
"end_location": {
"column": 1,
"row": 3
},
"location": {
"column": 1,
"row": 2
}
}
],
"message": "Remove unused import: `os`"
},
"location": {
"column": 8,
"row": 2
},
"message": "`os` imported but unused",
"noqa_row": 2,
"url": "https://docs.astral.sh/ruff/rules/unused-import"
}
]
----- stderr -----
warning: The option `format` has been deprecated to avoid ambiguity with Ruff's upcoming formatter. Use `output-format` instead.
"###);
Ok(())
}
1 change: 0 additions & 1 deletion crates/ruff_dev/src/format_dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,6 @@ fn format_dir_entry(

let settings = resolver.resolve(&path, pyproject_config);
// That's a bad way of doing this but it's not worth doing something better for format_dev
// TODO(micha) use formatter settings instead
if settings.formatter.line_width != LineWidth::default() {
options = options.with_line_width(settings.formatter.line_width);
}
Expand Down
6 changes: 5 additions & 1 deletion crates/ruff_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ use ruff_macros::CacheKey;
use ruff_text_size::{TextRange, TextSize};

#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, CacheKey)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "kebab-case")
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum IndentStyle {
Expand Down
3 changes: 1 addition & 2 deletions crates/ruff_formatter/src/printer/printer_options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
use ruff_macros::CacheKey;

/// Options that affect how the [`crate::Printer`] prints the format tokens
#[derive(Clone, Debug, Eq, PartialEq, Default)]
Expand Down Expand Up @@ -121,7 +120,7 @@ impl SourceMapGeneration {
}
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LineEnding {
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos
Expand Down
4 changes: 3 additions & 1 deletion crates/ruff_python_formatter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ memchr = { workspace = true }
once_cell = { workspace = true }
rustc-hash = { workspace = true }
serde = { workspace = true, optional = true }
schemars = { workspace = true, optional = true }
smallvec = { workspace = true }
static_assertions = { workspace = true }
thiserror = { workspace = true }
Expand All @@ -52,4 +53,5 @@ required-features = ["serde"]

[features]
serde = ["dep:serde", "ruff_formatter/serde", "ruff_source_file/serde", "ruff_python_ast/serde"]
default = ["serde"]
schemars = ["dep:schemars", "ruff_formatter/schemars"]
default = []