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

Stabilize quote-style preserve #9922

Merged
merged 1 commit into from
Feb 12, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/ruff_python_formatter/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ pub enum QuoteStyle {
Preserve,
}

impl QuoteStyle {
pub const fn is_preserve(self) -> bool {
matches!(self, QuoteStyle::Preserve)
}
}

impl fmt::Display for QuoteStyle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand Down
8 changes: 5 additions & 3 deletions crates/ruff_python_formatter/src/other/string_literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ impl Format<PyFormatContext<'_>> for FormatStringLiteral<'_> {
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
let locator = f.context().locator();

let quote_style = if self.layout.is_docstring() {
// Per PEP 8 and PEP 257, always prefer double quotes for docstrings
let quote_style = f.options().quote_style();
let quote_style = if self.layout.is_docstring() && !quote_style.is_preserve() {
// Per PEP 8 and PEP 257, always prefer double quotes for docstrings,
// except when using quote-style=preserve
QuoteStyle::Double
} else {
f.options().quote_style()
quote_style
};

let normalized = StringPart::from_source(self.value.range(), &locator).normalize(
Expand Down
3 changes: 3 additions & 0 deletions crates/ruff_python_formatter/src/string/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ impl StringPart {
normalize_hex: bool,
) -> NormalizedString<'a> {
// Per PEP 8, always prefer double quotes for triple-quoted strings.
// Except when using quote-style-preserve.
let preferred_style = if self.quotes.triple {
// ... unless we're formatting a code snippet inside a docstring,
// then we specifically want to invert our quote style to avoid
Expand Down Expand Up @@ -354,6 +355,8 @@ impl StringPart {
// if it doesn't have perfect alignment with PEP8.
if let Some(quote) = parent_docstring_quote_char {
QuoteStyle::from(quote.invert())
} else if configured_style.is_preserve() {
QuoteStyle::Preserve
} else {
QuoteStyle::Double
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,21 +263,21 @@ rb"rb double"
rb'br single'
rb"br double"

"""single triple"""
'''single triple'''
"""double triple"""
r"""r single triple"""
r'''r single triple'''
r"""r double triple"""
f"""f single triple"""
f'''f single triple'''
f"""f double triple"""
rf"""fr single triple"""
rf'''fr single triple'''
rf"""fr double triple"""
rf"""rf single triple"""
rf'''rf single triple'''
rf"""rf double triple"""
b"""b single triple"""
b'''b single triple'''
b"""b double triple"""
rb"""rb single triple"""
rb'''rb single triple'''
rb"""rb double triple"""
rb"""br single triple"""
rb'''br single triple'''
rb"""br double triple"""

'single1' 'single2'
Expand All @@ -287,7 +287,7 @@ rb"""br double triple"""


def docstring_single_triple():
"""single triple"""
'''single triple'''


def docstring_double_triple():
Expand All @@ -299,7 +299,7 @@ def docstring_double():


def docstring_single():
"single"
'single'
```


Expand All @@ -308,8 +308,7 @@ def docstring_single():
--- Stable
+++ Preview
@@ -1,4 +1,5 @@
-'single' # this string is treated as a docstring
+"single" # this string is treated as a docstring
'single' # this string is treated as a docstring
+
"double"
r'r single'
Expand Down
6 changes: 0 additions & 6 deletions crates/ruff_workspace/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,6 @@ impl Configuration {
PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled,
};

if quote_style == QuoteStyle::Preserve && !format_preview.is_enabled() {
return Err(anyhow!(
"'quote-style = preserve' is a preview only feature. Run with '--preview' to enable it."
));
}

let formatter = FormatterSettings {
exclude: FilePatternSet::try_from_iter(format.exclude.unwrap_or_default())?,
extension: self.extension.clone().unwrap_or_default(),
Expand Down
22 changes: 11 additions & 11 deletions crates/ruff_workspace/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2942,28 +2942,28 @@ pub struct FormatOptions {
)]
pub indent_style: Option<IndentStyle>,

/// Configures the preferred quote character for strings. Valid options are:
///
/// Configures the preferred quote character for strings. The recommended options are
/// * `double` (default): Use double quotes `"`
/// * `single`: Use single quotes `'`
/// * `preserve` (preview only): Keeps the existing quote character. We don't recommend using this option except for projects
/// that already use a mixture of single and double quotes and can't migrate to using double or single quotes.
///
/// In compliance with [PEP 8](https://peps.python.org/pep-0008/) and [PEP 257](https://peps.python.org/pep-0257/),
/// Ruff prefers double quotes for multiline strings and docstrings, regardless of the
/// configured quote style.
/// Ruff prefers double quotes for triple quoted strings and docstrings even when using `quote-style = "single"`.
///
/// Ruff may also deviate from using the configured quotes if doing so requires
/// escaping quote characters within the string. For example, given:
/// Ruff deviates from using the configured quotes if doing so prevents the need for
/// escaping quote characters inside the string:
///
/// ```python
/// a = "a string without any quotes"
/// b = "It's monday morning"
/// ```
///
/// Ruff will change `a` to use single quotes when using `quote-style = "single"`. However,
/// `b` remains unchanged, as converting to single quotes requires escaping the inner `'`,
/// which leads to less readable code: `'It\'s monday morning'`. This does not apply when using `preserve`.
/// Ruff will change the quotes of the string assigned to `a` to single quotes when using `quote-style = "single"`.
/// However, ruff uses double quotes for he string assigned to `b` because using single quotes would require escaping the `'`,
/// which leads to the less readable code: `'It\'s monday morning'`.
///
/// In addition, Ruff supports the quote style `preserve` for projects that already use
/// a mixture of single and double quotes and can't migrate to the `double` or `single` style.
/// The quote style `preserve` leaves the quotes of all strings unchanged.
#[option(
default = r#"double"#,
value_type = r#""double" | "single" | "preserve""#,
Expand Down
2 changes: 1 addition & 1 deletion ruff.schema.json

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

Loading