Skip to content
This repository was archived by the owner on Nov 19, 2021. It is now read-only.

Commit 5540354

Browse files
committed
Add an option for --single-quote, but strongly prefer double quote in readme.
1 parent b2067aa commit 5540354

File tree

2 files changed

+45
-17
lines changed

2 files changed

+45
-17
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ black [OPTIONS] [SRC]...
6868
6969
Options:
7070
-l, --line-length INTEGER Where to wrap around. [default: 88]
71+
--single-quote Use single quotes instead of double quotes in
72+
strings except for triple-quoted strings.
7173
--check Don't write the files back, just return the
7274
status. Return code 0 means nothing would
7375
change. Return code 1 means some files would be
@@ -341,6 +343,9 @@ a one double-quote regardless of fonts and syntax highlighting used.
341343
On top of this, double quotes for strings are consistent with C which
342344
Python interacts a lot with.
343345

346+
> While we strongly recommend double quotes, we also provide a
347+
> `--single-quote` option if you prefer.
348+
344349
On certain keyboard layouts like US English, typing single quotes is
345350
a bit easier than double quotes. The latter requires use of the Shift
346351
key. My recommendation here is to keep using whatever is faster to type

black.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from blib2to3.pgen2.parse import ParseError
4545

4646

47-
__version__ = "18.5b1"
47+
__version__ = "18.5z1"
4848
DEFAULT_LINE_LENGTH = 88
4949
CACHE_DIR = Path(user_cache_dir("black", version=__version__))
5050

@@ -126,6 +126,7 @@ class FileMode(Flag):
126126
AUTO_DETECT = 0
127127
PYTHON36 = 1
128128
PYI = 2
129+
SINGLE_QUOTE = 32
129130

130131

131132
@click.command()
@@ -137,6 +138,11 @@ class FileMode(Flag):
137138
help="How many character per line to allow.",
138139
show_default=True,
139140
)
141+
@click.option(
142+
"--single-quote",
143+
is_flag=True,
144+
help="Use single quotes instead of double quotes in strings.",
145+
)
140146
@click.option(
141147
"--check",
142148
is_flag=True,
@@ -195,6 +201,7 @@ def main(
195201
ctx: click.Context,
196202
line_length: int,
197203
check: bool,
204+
single_quote: bool,
198205
diff: bool,
199206
fast: bool,
200207
pyi: bool,
@@ -227,6 +234,8 @@ def main(
227234
mode |= FileMode.PYTHON36
228235
if pyi:
229236
mode |= FileMode.PYI
237+
if single_quote:
238+
mode |= FileMode.SINGLE_QUOTE
230239
report = Report(check=check, quiet=quiet)
231240
if len(sources) == 0:
232241
out("No paths given. Nothing to do 😴")
@@ -487,8 +496,11 @@ def format_str(
487496
future_imports = get_future_imports(src_node)
488497
is_pyi = bool(mode & FileMode.PYI)
489498
py36 = bool(mode & FileMode.PYTHON36) or is_python36(src_node)
499+
single_quote = bool(mode & FileMode.SINGLE_QUOTE)
490500
lines = LineGenerator(
491-
remove_u_prefix=py36 or "unicode_literals" in future_imports, is_pyi=is_pyi
501+
remove_u_prefix=py36 or "unicode_literals" in future_imports,
502+
is_pyi=is_pyi,
503+
single_quote=single_quote,
492504
)
493505
elt = EmptyLineTracker(is_pyi=is_pyi)
494506
empty_line = Line()
@@ -1286,6 +1298,7 @@ class LineGenerator(Visitor[Line]):
12861298
"""
12871299

12881300
is_pyi: bool = False
1301+
single_quote: bool = False
12891302
current_line: Line = Factory(Line)
12901303
remove_u_prefix: bool = False
12911304

@@ -1356,7 +1369,7 @@ def visit_default(self, node: LN) -> Iterator[Line]:
13561369
normalize_prefix(node, inside_brackets=any_open_brackets)
13571370
if node.type == token.STRING:
13581371
normalize_string_prefix(node, remove_u_prefix=self.remove_u_prefix)
1359-
normalize_string_quotes(node)
1372+
normalize_string_quotes(node, single_quote=self.single_quote)
13601373
if node.type not in WHITESPACE:
13611374
self.current_line.append(node)
13621375
yield from super().visit_default(node)
@@ -2313,7 +2326,7 @@ def normalize_string_prefix(leaf: Leaf, remove_u_prefix: bool = False) -> None:
23132326
leaf.value = f"{new_prefix}{match.group(2)}"
23142327

23152328

2316-
def normalize_string_quotes(leaf: Leaf) -> None:
2329+
def normalize_string_quotes(leaf: Leaf, single_quote: bool = False) -> None:
23172330
"""Prefer double quotes but only if it doesn't cause more escaping.
23182331
23192332
Adds or removes backslashes as appropriate. Doesn't parse and fix
@@ -2322,18 +2335,28 @@ def normalize_string_quotes(leaf: Leaf) -> None:
23222335
Note: Mutates its argument.
23232336
"""
23242337
value = leaf.value.lstrip("furbFURB")
2325-
if value[:3] == '"""':
2338+
2339+
quote_char = '"'
2340+
alt_quote_char = "'"
2341+
triple_quote_chars = '"""'
2342+
alt_triple_quote_chars = "'''"
2343+
2344+
if single_quote:
2345+
quote_char = "'"
2346+
alt_quote_char = '"'
2347+
2348+
if value[:3] == triple_quote_chars:
23262349
return
23272350

2328-
elif value[:3] == "'''":
2329-
orig_quote = "'''"
2330-
new_quote = '"""'
2331-
elif value[0] == '"':
2332-
orig_quote = '"'
2333-
new_quote = "'"
2351+
elif value[:3] == alt_triple_quote_chars:
2352+
orig_quote = alt_triple_quote_chars
2353+
new_quote = triple_quote_chars
2354+
elif value[0] == quote_char:
2355+
orig_quote = quote_char
2356+
new_quote = alt_quote_char
23342357
else:
2335-
orig_quote = "'"
2336-
new_quote = '"'
2358+
orig_quote = alt_quote_char
2359+
new_quote = quote_char
23372360
first_quote_pos = leaf.value.find(orig_quote)
23382361
if first_quote_pos == -1:
23392362
return # There's an internal error
@@ -2360,16 +2383,16 @@ def normalize_string_quotes(leaf: Leaf) -> None:
23602383
leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
23612384
new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
23622385
new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
2363-
if new_quote == '"""' and new_body[-1] == '"':
2386+
if new_quote == triple_quote_chars and new_body[-1] == triple_quote_chars[0]:
23642387
# edge case:
2365-
new_body = new_body[:-1] + '\\"'
2388+
new_body = new_body[:-1] + "\\" + triple_quote_chars[0]
23662389
orig_escape_count = body.count("\\")
23672390
new_escape_count = new_body.count("\\")
23682391
if new_escape_count > orig_escape_count:
23692392
return # Do not introduce more escaping
23702393

2371-
if new_escape_count == orig_escape_count and orig_quote == '"':
2372-
return # Prefer double quotes
2394+
if new_escape_count == orig_escape_count and orig_quote == quote_char:
2395+
return
23732396

23742397
leaf.value = f"{prefix}{new_quote}{new_body}{new_quote}"
23752398

0 commit comments

Comments
 (0)