Skip to content

Commit

Permalink
Add most formatter options to ruff.toml / pyproject.toml
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Sep 22, 2023
1 parent 814403c commit bc3127d
Show file tree
Hide file tree
Showing 23 changed files with 777 additions and 144 deletions.
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
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
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
@@ -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(())
}
6 changes: 5 additions & 1 deletion crates/ruff_formatter/src/lib.rs
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
@@ -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
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 = []
@@ -1,18 +1,18 @@
[
{
"indent_style": "Space",
"indent_style": "space",
"indent_width": 4
},
{
"indent_style": "Space",
"indent_style": "space",
"indent_width": 2
},
{
"indent_style": "Tab",
"indent_style": "tab",
"indent_width": 8
},
{
"indent_style": "Tab",
"indent_style": "tab",
"indent_width": 4
}
]

0 comments on commit bc3127d

Please sign in to comment.