123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- #
- # Copyright (C) 2009-2020 the sqlparse authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of python-sqlparse and is released under
- # the BSD License: https://opensource.org/licenses/BSD-3-Clause
-
- """SQL formatter"""
-
- from sqlparse import filters
- from sqlparse.exceptions import SQLParseError
-
-
- def validate_options(options):
- """Validates options."""
- kwcase = options.get('keyword_case')
- if kwcase not in [None, 'upper', 'lower', 'capitalize']:
- raise SQLParseError('Invalid value for keyword_case: '
- '{!r}'.format(kwcase))
-
- idcase = options.get('identifier_case')
- if idcase not in [None, 'upper', 'lower', 'capitalize']:
- raise SQLParseError('Invalid value for identifier_case: '
- '{!r}'.format(idcase))
-
- ofrmt = options.get('output_format')
- if ofrmt not in [None, 'sql', 'python', 'php']:
- raise SQLParseError('Unknown output format: '
- '{!r}'.format(ofrmt))
-
- strip_comments = options.get('strip_comments', False)
- if strip_comments not in [True, False]:
- raise SQLParseError('Invalid value for strip_comments: '
- '{!r}'.format(strip_comments))
-
- space_around_operators = options.get('use_space_around_operators', False)
- if space_around_operators not in [True, False]:
- raise SQLParseError('Invalid value for use_space_around_operators: '
- '{!r}'.format(space_around_operators))
-
- strip_ws = options.get('strip_whitespace', False)
- if strip_ws not in [True, False]:
- raise SQLParseError('Invalid value for strip_whitespace: '
- '{!r}'.format(strip_ws))
-
- truncate_strings = options.get('truncate_strings')
- if truncate_strings is not None:
- try:
- truncate_strings = int(truncate_strings)
- except (ValueError, TypeError):
- raise SQLParseError('Invalid value for truncate_strings: '
- '{!r}'.format(truncate_strings))
- if truncate_strings <= 1:
- raise SQLParseError('Invalid value for truncate_strings: '
- '{!r}'.format(truncate_strings))
- options['truncate_strings'] = truncate_strings
- options['truncate_char'] = options.get('truncate_char', '[...]')
-
- indent_columns = options.get('indent_columns', False)
- if indent_columns not in [True, False]:
- raise SQLParseError('Invalid value for indent_columns: '
- '{!r}'.format(indent_columns))
- elif indent_columns:
- options['reindent'] = True # enforce reindent
- options['indent_columns'] = indent_columns
-
- reindent = options.get('reindent', False)
- if reindent not in [True, False]:
- raise SQLParseError('Invalid value for reindent: '
- '{!r}'.format(reindent))
- elif reindent:
- options['strip_whitespace'] = True
-
- reindent_aligned = options.get('reindent_aligned', False)
- if reindent_aligned not in [True, False]:
- raise SQLParseError('Invalid value for reindent_aligned: '
- '{!r}'.format(reindent))
- elif reindent_aligned:
- options['strip_whitespace'] = True
-
- indent_after_first = options.get('indent_after_first', False)
- if indent_after_first not in [True, False]:
- raise SQLParseError('Invalid value for indent_after_first: '
- '{!r}'.format(indent_after_first))
- options['indent_after_first'] = indent_after_first
-
- indent_tabs = options.get('indent_tabs', False)
- if indent_tabs not in [True, False]:
- raise SQLParseError('Invalid value for indent_tabs: '
- '{!r}'.format(indent_tabs))
- elif indent_tabs:
- options['indent_char'] = '\t'
- else:
- options['indent_char'] = ' '
-
- indent_width = options.get('indent_width', 2)
- try:
- indent_width = int(indent_width)
- except (TypeError, ValueError):
- raise SQLParseError('indent_width requires an integer')
- if indent_width < 1:
- raise SQLParseError('indent_width requires a positive integer')
- options['indent_width'] = indent_width
-
- wrap_after = options.get('wrap_after', 0)
- try:
- wrap_after = int(wrap_after)
- except (TypeError, ValueError):
- raise SQLParseError('wrap_after requires an integer')
- if wrap_after < 0:
- raise SQLParseError('wrap_after requires a positive integer')
- options['wrap_after'] = wrap_after
-
- comma_first = options.get('comma_first', False)
- if comma_first not in [True, False]:
- raise SQLParseError('comma_first requires a boolean value')
- options['comma_first'] = comma_first
-
- right_margin = options.get('right_margin')
- if right_margin is not None:
- try:
- right_margin = int(right_margin)
- except (TypeError, ValueError):
- raise SQLParseError('right_margin requires an integer')
- if right_margin < 10:
- raise SQLParseError('right_margin requires an integer > 10')
- options['right_margin'] = right_margin
-
- return options
-
-
- def build_filter_stack(stack, options):
- """Setup and return a filter stack.
-
- Args:
- stack: :class:`~sqlparse.filters.FilterStack` instance
- options: Dictionary with options validated by validate_options.
- """
- # Token filter
- if options.get('keyword_case'):
- stack.preprocess.append(
- filters.KeywordCaseFilter(options['keyword_case']))
-
- if options.get('identifier_case'):
- stack.preprocess.append(
- filters.IdentifierCaseFilter(options['identifier_case']))
-
- if options.get('truncate_strings'):
- stack.preprocess.append(filters.TruncateStringFilter(
- width=options['truncate_strings'], char=options['truncate_char']))
-
- if options.get('use_space_around_operators', False):
- stack.enable_grouping()
- stack.stmtprocess.append(filters.SpacesAroundOperatorsFilter())
-
- # After grouping
- if options.get('strip_comments'):
- stack.enable_grouping()
- stack.stmtprocess.append(filters.StripCommentsFilter())
-
- if options.get('strip_whitespace') or options.get('reindent'):
- stack.enable_grouping()
- stack.stmtprocess.append(filters.StripWhitespaceFilter())
-
- if options.get('reindent'):
- stack.enable_grouping()
- stack.stmtprocess.append(
- filters.ReindentFilter(
- char=options['indent_char'],
- width=options['indent_width'],
- indent_after_first=options['indent_after_first'],
- indent_columns=options['indent_columns'],
- wrap_after=options['wrap_after'],
- comma_first=options['comma_first']))
-
- if options.get('reindent_aligned', False):
- stack.enable_grouping()
- stack.stmtprocess.append(
- filters.AlignedIndentFilter(char=options['indent_char']))
-
- if options.get('right_margin'):
- stack.enable_grouping()
- stack.stmtprocess.append(
- filters.RightMarginFilter(width=options['right_margin']))
-
- # Serializer
- if options.get('output_format'):
- frmt = options['output_format']
- if frmt.lower() == 'php':
- fltr = filters.OutputPHPFilter()
- elif frmt.lower() == 'python':
- fltr = filters.OutputPythonFilter()
- else:
- fltr = None
- if fltr is not None:
- stack.postprocess.append(fltr)
-
- return stack
|