Skip to content
Open
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
27 changes: 26 additions & 1 deletion src/python_minifier/token_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@
import sys


def _shortest_repr(value):
"""
The shortest repr of a str, preferring single quotes on a tie.

repr() only switches to double quotes when the string contains a single
quote and no double quote, so a string containing more single quotes than
double quotes is rendered with every single quote escaped. Try the double
quoted form too and keep whichever is shorter.
"""

s = repr(value)

if "'" not in value or '"' not in value:
return s

prefix = s[:s.index("'")]
body = s[len(prefix) + 1:-1]
double_quoted = prefix + '"' + body.replace("\\'", "'").replace('"', '\\"') + '"'

if len(double_quoted) < len(s):
return double_quoted

return s


class TokenTypes(object):
NoToken = 0
Identifier = 1
Expand Down Expand Up @@ -145,7 +170,7 @@ def keyword(self, kw):

def stringliteral(self, value):
"""Add a string literal to the output code."""
s = repr(value)
s = _shortest_repr(value)

if sys.version_info < (3, 0) and self.unicode_literals:
if s[0] == 'u':
Expand Down
22 changes: 22 additions & 0 deletions test/test_string_quotes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Tests for the quote style chosen for string literals."""

from python_minifier import minify


def test_no_quotes_uses_single_quotes():
assert minify('print("")') == "print('')"


def test_single_quote_in_string_uses_double_quotes():
assert minify('print(\'\\\'\')') == 'print("\'")'


def test_tie_prefers_single_quotes():
assert minify('print("\'\\"")') == 'print(\'\\\'"\')'


def test_more_single_quotes_than_double_uses_double_quotes():
# A string with more single quotes than double quotes must not be
# rendered with every single quote escaped, which made the output
# longer than the input.
assert minify('print("\'\\"\'")') == 'print("\'\\"\'")'