Skip to content

Commit

Permalink
Always prefer double quotes for docstrings and triple-quoted srings
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Sep 27, 2023
1 parent e863fa5 commit 98b5823
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 42 deletions.
30 changes: 22 additions & 8 deletions crates/ruff_python_formatter/src/expression/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,17 +323,25 @@ impl StringPart {
self,
quoting: Quoting,
locator: &'a Locator,
quote_style: QuoteStyle,
configured_style: QuoteStyle,
) -> NormalizedString<'a> {
// Per PEP 8 and PEP 257, always prefer double quotes for docstrings and triple-quoted
// strings. (We assume docstrings are always triple-quoted.)
let preferred_style = if self.quotes.triple {
QuoteStyle::Double
} else {
configured_style
};

let raw_content = locator.slice(self.content_range);

let preferred_quotes = match quoting {
Quoting::Preserve => self.quotes,
Quoting::CanChange => {
if self.prefix.is_raw_string() {
preferred_quotes_raw(raw_content, self.quotes, quote_style)
preferred_quotes_raw(raw_content, self.quotes, preferred_style)
} else {
preferred_quotes(raw_content, self.quotes, quote_style)
preferred_quotes(raw_content, self.quotes, preferred_style)
}
}
};
Expand Down Expand Up @@ -460,8 +468,9 @@ impl Format<PyFormatContext<'_>> for StringPrefix {
}
}

/// Detects the preferred quotes for raw string `input`.
/// The configured quote style is preferred unless `input` contains unescaped quotes of the
/// Detects the preferred quotes for a raw string.
///
/// The configured quote style is preferred unless the string contains unescaped quotes of the
/// configured style. For example, `r"foo"` is preferred over `r'foo'` if the configured
/// quote style is double quotes.
fn preferred_quotes_raw(
Expand Down Expand Up @@ -515,9 +524,14 @@ fn preferred_quotes_raw(
}
}

/// Detects the preferred quotes for `input`.
/// * single quoted strings: The preferred quote style is the one that requires less escape sequences.
/// * triple quoted strings: Use double quotes except the string contains a sequence of `"""`.
/// Detects the preferred quote style for a string.
///
/// For single quoted strings, the preferred quote style is the configured quote style, unless the
/// alternative quote style would require fewer escapes.
///
/// For triple quoted strings, the preferred quote style is always used, unless the string contains
/// a triplet of the quote character (e.g., if double quotes are preferred, double quotes will be
/// used unless the string contains `"""`).
fn preferred_quotes(
input: &str,
quotes: StringQuotes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,17 +320,17 @@ if True:
b'This string will not include \
backslashes or newline characters.'
b'''Multiline
b"""Multiline
String \"
'''
"""
b'''Multiline
b"""Multiline
String \'
'''
"""
b'''Multiline
b"""Multiline
String ""
'''
"""
b'''Multiline
String """
Expand All @@ -346,9 +346,9 @@ String '''
b"""Multiline
String '"""
b'''Multiline
b"""Multiline
String \"\"\"
'''
"""
# String continuation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,17 +365,17 @@ if True:
'This string will not include \
backslashes or newline characters.'
'''Multiline
"""Multiline
String \"
'''
"""
'''Multiline
"""Multiline
String \'
'''
"""
'''Multiline
"""Multiline
String ""
'''
"""
'''Multiline
String """
Expand All @@ -391,9 +391,9 @@ String '''
"""Multiline
String '"""
'''Multiline
"""Multiline
String \"\"\"
'''
"""
# String continuation
Expand Down Expand Up @@ -471,16 +471,16 @@ test_particular = [
# Regression test for https://github.com/astral-sh/ruff/issues/5893
x = (
'''aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'''
'''bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'''
"""aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"""
"""bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"""
)
x = (
f'''aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'''
f'''bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'''
f"""aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"""
f"""bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"""
)
x = (
b'''aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'''
b'''bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'''
b"""aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"""
b"""bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"""
)
# https://github.com/astral-sh/ruff/issues/7460
Expand Down
28 changes: 17 additions & 11 deletions crates/ruff_workspace/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2461,42 +2461,48 @@ pub struct FormatOptions {
default = "false",
value_type = "bool",
example = r#"
# Enable preview style formatting
# Enable preview style formatting.
preview = true
"#
)]
pub preview: Option<bool>,

/// Whether to use 4 spaces or hard tabs for indenting code.
///
/// Defaults to 4 spaces. We care about accessibility; if you do not need tabs for accessibility, we do not recommend you use them.
/// Defaults to 4 spaces. We care about accessibility; if you do not need tabs for
/// accessibility, we do not recommend you use them.
#[option(
default = "space",
value_type = r#""space" | "tab""#,
example = r#"
# Use tabs instead of 4 space indentation
# Use tabs instead of 4 space indentation.
indent-style = "tab"
"#
)]
pub indent_style: Option<IndentStyle>,

/// Whether to prefer single `'` or double `"` quotes for strings and docstrings.
/// Whether to prefer single `'` or double `"` quotes for strings. Defaults to double quotes.
///
/// Ruff may deviate from this option if using the configured quotes would require more escaped 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 may also deviate from this option if using the configured quotes would require
/// escaping quote characters within the string. For example, given:
///
/// ```python
/// a = "It's monday morning"
/// b = "a string without any quotes"
/// a = "a string without any quotes"
/// b = "It's monday morning"
/// ```
///
/// Ruff leaves `a` unchanged when using `quote-style = "single"` because it is otherwise
/// necessary to escape the `'` which leads to less readable code: `'It\'s monday morning'`.
/// Ruff changes the quotes of `b` to use single quotes.
/// Ruff will change `a` to use single quotes when using `quote-style = "single"`. However,
/// `a` will be unchanged, as converting to single quotes would require the inner `'` to be
/// escaped, which leads to less readable code: `'It\'s monday morning'`.
#[option(
default = r#"double"#,
value_type = r#""double" | "single""#,
example = r#"
# Prefer single quotes over double quotes
# Prefer single quotes over double quotes.
quote-style = "single"
"#
)]
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.

0 comments on commit 98b5823

Please sign in to comment.