You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

formatter.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2009-2018 the sqlparse authors and contributors
  4. # <see AUTHORS file>
  5. #
  6. # This module is part of python-sqlparse and is released under
  7. # the BSD License: https://opensource.org/licenses/BSD-3-Clause
  8. """SQL formatter"""
  9. from sqlparse import filters
  10. from sqlparse.exceptions import SQLParseError
  11. def validate_options(options):
  12. """Validates options."""
  13. kwcase = options.get('keyword_case')
  14. if kwcase not in [None, 'upper', 'lower', 'capitalize']:
  15. raise SQLParseError('Invalid value for keyword_case: '
  16. '{0!r}'.format(kwcase))
  17. idcase = options.get('identifier_case')
  18. if idcase not in [None, 'upper', 'lower', 'capitalize']:
  19. raise SQLParseError('Invalid value for identifier_case: '
  20. '{0!r}'.format(idcase))
  21. ofrmt = options.get('output_format')
  22. if ofrmt not in [None, 'sql', 'python', 'php']:
  23. raise SQLParseError('Unknown output format: '
  24. '{0!r}'.format(ofrmt))
  25. strip_comments = options.get('strip_comments', False)
  26. if strip_comments not in [True, False]:
  27. raise SQLParseError('Invalid value for strip_comments: '
  28. '{0!r}'.format(strip_comments))
  29. space_around_operators = options.get('use_space_around_operators', False)
  30. if space_around_operators not in [True, False]:
  31. raise SQLParseError('Invalid value for use_space_around_operators: '
  32. '{0!r}'.format(space_around_operators))
  33. strip_ws = options.get('strip_whitespace', False)
  34. if strip_ws not in [True, False]:
  35. raise SQLParseError('Invalid value for strip_whitespace: '
  36. '{0!r}'.format(strip_ws))
  37. truncate_strings = options.get('truncate_strings')
  38. if truncate_strings is not None:
  39. try:
  40. truncate_strings = int(truncate_strings)
  41. except (ValueError, TypeError):
  42. raise SQLParseError('Invalid value for truncate_strings: '
  43. '{0!r}'.format(truncate_strings))
  44. if truncate_strings <= 1:
  45. raise SQLParseError('Invalid value for truncate_strings: '
  46. '{0!r}'.format(truncate_strings))
  47. options['truncate_strings'] = truncate_strings
  48. options['truncate_char'] = options.get('truncate_char', '[...]')
  49. indent_columns = options.get('indent_columns', False)
  50. if indent_columns not in [True, False]:
  51. raise SQLParseError('Invalid value for indent_columns: '
  52. '{0!r}'.format(indent_columns))
  53. elif indent_columns:
  54. options['reindent'] = True # enforce reindent
  55. options['indent_columns'] = indent_columns
  56. reindent = options.get('reindent', False)
  57. if reindent not in [True, False]:
  58. raise SQLParseError('Invalid value for reindent: '
  59. '{0!r}'.format(reindent))
  60. elif reindent:
  61. options['strip_whitespace'] = True
  62. reindent_aligned = options.get('reindent_aligned', False)
  63. if reindent_aligned not in [True, False]:
  64. raise SQLParseError('Invalid value for reindent_aligned: '
  65. '{0!r}'.format(reindent))
  66. elif reindent_aligned:
  67. options['strip_whitespace'] = True
  68. indent_after_first = options.get('indent_after_first', False)
  69. if indent_after_first not in [True, False]:
  70. raise SQLParseError('Invalid value for indent_after_first: '
  71. '{0!r}'.format(indent_after_first))
  72. options['indent_after_first'] = indent_after_first
  73. indent_tabs = options.get('indent_tabs', False)
  74. if indent_tabs not in [True, False]:
  75. raise SQLParseError('Invalid value for indent_tabs: '
  76. '{0!r}'.format(indent_tabs))
  77. elif indent_tabs:
  78. options['indent_char'] = '\t'
  79. else:
  80. options['indent_char'] = ' '
  81. indent_width = options.get('indent_width', 2)
  82. try:
  83. indent_width = int(indent_width)
  84. except (TypeError, ValueError):
  85. raise SQLParseError('indent_width requires an integer')
  86. if indent_width < 1:
  87. raise SQLParseError('indent_width requires a positive integer')
  88. options['indent_width'] = indent_width
  89. wrap_after = options.get('wrap_after', 0)
  90. try:
  91. wrap_after = int(wrap_after)
  92. except (TypeError, ValueError):
  93. raise SQLParseError('wrap_after requires an integer')
  94. if wrap_after < 0:
  95. raise SQLParseError('wrap_after requires a positive integer')
  96. options['wrap_after'] = wrap_after
  97. comma_first = options.get('comma_first', False)
  98. if comma_first not in [True, False]:
  99. raise SQLParseError('comma_first requires a boolean value')
  100. options['comma_first'] = comma_first
  101. right_margin = options.get('right_margin')
  102. if right_margin is not None:
  103. try:
  104. right_margin = int(right_margin)
  105. except (TypeError, ValueError):
  106. raise SQLParseError('right_margin requires an integer')
  107. if right_margin < 10:
  108. raise SQLParseError('right_margin requires an integer > 10')
  109. options['right_margin'] = right_margin
  110. return options
  111. def build_filter_stack(stack, options):
  112. """Setup and return a filter stack.
  113. Args:
  114. stack: :class:`~sqlparse.filters.FilterStack` instance
  115. options: Dictionary with options validated by validate_options.
  116. """
  117. # Token filter
  118. if options.get('keyword_case'):
  119. stack.preprocess.append(
  120. filters.KeywordCaseFilter(options['keyword_case']))
  121. if options.get('identifier_case'):
  122. stack.preprocess.append(
  123. filters.IdentifierCaseFilter(options['identifier_case']))
  124. if options.get('truncate_strings'):
  125. stack.preprocess.append(filters.TruncateStringFilter(
  126. width=options['truncate_strings'], char=options['truncate_char']))
  127. if options.get('use_space_around_operators', False):
  128. stack.enable_grouping()
  129. stack.stmtprocess.append(filters.SpacesAroundOperatorsFilter())
  130. # After grouping
  131. if options.get('strip_comments'):
  132. stack.enable_grouping()
  133. stack.stmtprocess.append(filters.StripCommentsFilter())
  134. if options.get('strip_whitespace') or options.get('reindent'):
  135. stack.enable_grouping()
  136. stack.stmtprocess.append(filters.StripWhitespaceFilter())
  137. if options.get('reindent'):
  138. stack.enable_grouping()
  139. stack.stmtprocess.append(
  140. filters.ReindentFilter(
  141. char=options['indent_char'],
  142. width=options['indent_width'],
  143. indent_after_first=options['indent_after_first'],
  144. indent_columns=options['indent_columns'],
  145. wrap_after=options['wrap_after'],
  146. comma_first=options['comma_first']))
  147. if options.get('reindent_aligned', False):
  148. stack.enable_grouping()
  149. stack.stmtprocess.append(
  150. filters.AlignedIndentFilter(char=options['indent_char']))
  151. if options.get('right_margin'):
  152. stack.enable_grouping()
  153. stack.stmtprocess.append(
  154. filters.RightMarginFilter(width=options['right_margin']))
  155. # Serializer
  156. if options.get('output_format'):
  157. frmt = options['output_format']
  158. if frmt.lower() == 'php':
  159. fltr = filters.OutputPHPFilter()
  160. elif frmt.lower() == 'python':
  161. fltr = filters.OutputPythonFilter()
  162. else:
  163. fltr = None
  164. if fltr is not None:
  165. stack.postprocess.append(fltr)
  166. return stack