Skip to content

Commit 204b779

Browse files
committed
Add option to truncate long string literals.
1 parent 223e410 commit 204b779

5 files changed

Lines changed: 79 additions & 0 deletions

File tree

CHANGES

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
Development Version
2+
-------------------
3+
4+
Enhancements
5+
* New option to truncate long string literals when formatting.
6+
7+
18
Release 0.1.8 (Jun 29, 2013)
29
----------------------------
310

docs/source/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ The :meth:`~sqlparse.format` function accepts the following keyword arguments.
3535
``strip_comments``
3636
If ``True`` comments are removed from the statements.
3737

38+
``truncate_strings``
39+
If ``truncate_strings`` is a positive integer, string literals longer than
40+
the given value will be truncated.
41+
42+
``truncate_char`` (default: "[...]")
43+
If long string literals are truncated (see above) this value will be append
44+
to the truncated string.
45+
3846
``reindent``
3947
If ``True`` the indentations of the statements are changed.
4048

sqlparse/filters.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ def process(self, stack, stream):
4747
yield ttype, value
4848

4949

50+
class TruncateStringFilter:
51+
52+
def __init__(self, width, char):
53+
self.width = max(width, 1)
54+
self.char = unicode(char)
55+
56+
def process(self, stack, stream):
57+
for ttype, value in stream:
58+
if ttype is T.Literal.String.Single:
59+
if value[:2] == '\'\'':
60+
inner = value[2:-2]
61+
quote = u'\'\''
62+
else:
63+
inner = value[1:-1]
64+
quote = u'\''
65+
if len(inner) > self.width:
66+
value = u''.join((quote, inner[:self.width], self.char,
67+
quote))
68+
yield ttype, value
69+
70+
5071
class GetComments:
5172
"""Get the comments from a stack"""
5273
def process(self, stack, stream):

sqlparse/formatter.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ def validate_options(options):
3333
raise SQLParseError('Invalid value for strip_whitespace: %r'
3434
% strip_ws)
3535

36+
truncate_strings = options.get('truncate_strings', None)
37+
if truncate_strings is not None:
38+
try:
39+
truncate_strings = int(truncate_strings)
40+
except (ValueError, TypeError):
41+
raise SQLParseError('Invalid value for truncate_strings: %r'
42+
% truncate_strings)
43+
if truncate_strings <= 1:
44+
raise SQLParseError('Invalid value for truncate_strings: %r'
45+
% truncate_strings)
46+
options['truncate_strings'] = truncate_strings
47+
options['truncate_char'] = options.get('truncate_char', '[...]')
48+
3649
reindent = options.get('reindent', False)
3750
if reindent not in [True, False]:
3851
raise SQLParseError('Invalid value for reindent: %r'
@@ -84,6 +97,10 @@ def build_filter_stack(stack, options):
8497
stack.preprocess.append(
8598
filters.IdentifierCaseFilter(options['identifier_case']))
8699

100+
if options.get('truncate_strings', None) is not None:
101+
stack.preprocess.append(filters.TruncateStringFilter(
102+
width=options['truncate_strings'], char=options['truncate_char']))
103+
87104
# After grouping
88105
if options.get('strip_comments', False):
89106
stack.enable_grouping()

tests/test_format.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# -*- coding: utf-8 -*-
22

3+
import pytest
4+
35
from tests.utils import TestCaseBase
46

57
import sqlparse
@@ -283,3 +285,27 @@ def test_format_column_ordering(): # issue89
283285
' c2,',
284286
' c3;'])
285287
assert formatted == expected
288+
289+
290+
def test_truncate_strings():
291+
sql = 'update foo set value = \'' + 'x' * 1000 + '\';'
292+
formatted = sqlparse.format(sql, truncate_strings=10)
293+
assert formatted == 'update foo set value = \'xxxxxxxxxx[...]\';'
294+
formatted = sqlparse.format(sql, truncate_strings=3, truncate_char='YYY')
295+
assert formatted == 'update foo set value = \'xxxYYY\';'
296+
297+
298+
def test_truncate_strings_invalid_option():
299+
pytest.raises(SQLParseError, sqlparse.format,
300+
'foo', truncate_strings='bar')
301+
pytest.raises(SQLParseError, sqlparse.format,
302+
'foo', truncate_strings=-1)
303+
pytest.raises(SQLParseError, sqlparse.format,
304+
'foo', truncate_strings=0)
305+
306+
307+
@pytest.mark.parametrize('sql', ['select verrrylongcolumn from foo',
308+
'select "verrrylongcolumn" from "foo"'])
309+
def test_truncate_strings_doesnt_truncate_identifiers(sql):
310+
formatted = sqlparse.format(sql, truncate_strings=2)
311+
assert formatted == sql

0 commit comments

Comments
 (0)