Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlparse/formatter.py: 57%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

128 statements  

1# 

2# Copyright (C) 2009-2020 the sqlparse authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of python-sqlparse and is released under 

6# the BSD License: https://opensource.org/licenses/BSD-3-Clause 

7 

8"""SQL formatter""" 

9 

10from sqlparse import filters 

11from sqlparse.exceptions import SQLParseError 

12 

13 

14def validate_options(options): # noqa: C901 

15 """Validates options.""" 

16 kwcase = options.get('keyword_case') 

17 if kwcase not in [None, 'upper', 'lower', 'capitalize']: 

18 raise SQLParseError('Invalid value for keyword_case: ' 

19 '{!r}'.format(kwcase)) 

20 

21 idcase = options.get('identifier_case') 

22 if idcase not in [None, 'upper', 'lower', 'capitalize']: 

23 raise SQLParseError('Invalid value for identifier_case: ' 

24 '{!r}'.format(idcase)) 

25 

26 ofrmt = options.get('output_format') 

27 if ofrmt not in [None, 'sql', 'python', 'php']: 

28 raise SQLParseError('Unknown output format: ' 

29 '{!r}'.format(ofrmt)) 

30 

31 strip_comments = options.get('strip_comments', False) 

32 if strip_comments not in [True, False]: 

33 raise SQLParseError('Invalid value for strip_comments: ' 

34 '{!r}'.format(strip_comments)) 

35 

36 space_around_operators = options.get('use_space_around_operators', False) 

37 if space_around_operators not in [True, False]: 

38 raise SQLParseError('Invalid value for use_space_around_operators: ' 

39 '{!r}'.format(space_around_operators)) 

40 

41 strip_ws = options.get('strip_whitespace', False) 

42 if strip_ws not in [True, False]: 

43 raise SQLParseError('Invalid value for strip_whitespace: ' 

44 '{!r}'.format(strip_ws)) 

45 

46 truncate_strings = options.get('truncate_strings') 

47 if truncate_strings is not None: 

48 try: 

49 truncate_strings = int(truncate_strings) 

50 except (ValueError, TypeError): 

51 raise SQLParseError('Invalid value for truncate_strings: ' 

52 '{!r}'.format(truncate_strings)) 

53 if truncate_strings <= 1: 

54 raise SQLParseError('Invalid value for truncate_strings: ' 

55 '{!r}'.format(truncate_strings)) 

56 options['truncate_strings'] = truncate_strings 

57 options['truncate_char'] = options.get('truncate_char', '[...]') 

58 

59 indent_columns = options.get('indent_columns', False) 

60 if indent_columns not in [True, False]: 

61 raise SQLParseError('Invalid value for indent_columns: ' 

62 '{!r}'.format(indent_columns)) 

63 elif indent_columns: 

64 options['reindent'] = True # enforce reindent 

65 options['indent_columns'] = indent_columns 

66 

67 reindent = options.get('reindent', False) 

68 if reindent not in [True, False]: 

69 raise SQLParseError('Invalid value for reindent: ' 

70 '{!r}'.format(reindent)) 

71 elif reindent: 

72 options['strip_whitespace'] = True 

73 

74 reindent_aligned = options.get('reindent_aligned', False) 

75 if reindent_aligned not in [True, False]: 

76 raise SQLParseError('Invalid value for reindent_aligned: ' 

77 '{!r}'.format(reindent)) 

78 elif reindent_aligned: 

79 options['strip_whitespace'] = True 

80 

81 indent_after_first = options.get('indent_after_first', False) 

82 if indent_after_first not in [True, False]: 

83 raise SQLParseError('Invalid value for indent_after_first: ' 

84 '{!r}'.format(indent_after_first)) 

85 options['indent_after_first'] = indent_after_first 

86 

87 indent_tabs = options.get('indent_tabs', False) 

88 if indent_tabs not in [True, False]: 

89 raise SQLParseError('Invalid value for indent_tabs: ' 

90 '{!r}'.format(indent_tabs)) 

91 elif indent_tabs: 

92 options['indent_char'] = '\t' 

93 else: 

94 options['indent_char'] = ' ' 

95 

96 indent_width = options.get('indent_width', 2) 

97 try: 

98 indent_width = int(indent_width) 

99 except (TypeError, ValueError): 

100 raise SQLParseError('indent_width requires an integer') 

101 if indent_width < 1: 

102 raise SQLParseError('indent_width requires a positive integer') 

103 options['indent_width'] = indent_width 

104 

105 wrap_after = options.get('wrap_after', 0) 

106 try: 

107 wrap_after = int(wrap_after) 

108 except (TypeError, ValueError): 

109 raise SQLParseError('wrap_after requires an integer') 

110 if wrap_after < 0: 

111 raise SQLParseError('wrap_after requires a positive integer') 

112 options['wrap_after'] = wrap_after 

113 

114 comma_first = options.get('comma_first', False) 

115 if comma_first not in [True, False]: 

116 raise SQLParseError('comma_first requires a boolean value') 

117 options['comma_first'] = comma_first 

118 

119 compact = options.get('compact', False) 

120 if compact not in [True, False]: 

121 raise SQLParseError('compact requires a boolean value') 

122 options['compact'] = compact 

123 

124 right_margin = options.get('right_margin') 

125 if right_margin is not None: 

126 try: 

127 right_margin = int(right_margin) 

128 except (TypeError, ValueError): 

129 raise SQLParseError('right_margin requires an integer') 

130 if right_margin < 10: 

131 raise SQLParseError('right_margin requires an integer > 10') 

132 options['right_margin'] = right_margin 

133 

134 return options 

135 

136 

137def build_filter_stack(stack, options): 

138 """Setup and return a filter stack. 

139 

140 Args: 

141 stack: :class:`~sqlparse.filters.FilterStack` instance 

142 options: Dictionary with options validated by validate_options. 

143 """ 

144 # Token filter 

145 if options.get('keyword_case'): 

146 stack.preprocess.append( 

147 filters.KeywordCaseFilter(options['keyword_case'])) 

148 

149 if options.get('identifier_case'): 

150 stack.preprocess.append( 

151 filters.IdentifierCaseFilter(options['identifier_case'])) 

152 

153 if options.get('truncate_strings'): 

154 stack.preprocess.append(filters.TruncateStringFilter( 

155 width=options['truncate_strings'], char=options['truncate_char'])) 

156 

157 if options.get('use_space_around_operators', False): 

158 stack.enable_grouping() 

159 stack.stmtprocess.append(filters.SpacesAroundOperatorsFilter()) 

160 

161 # After grouping 

162 if options.get('strip_comments'): 

163 stack.enable_grouping() 

164 stack.stmtprocess.append(filters.StripCommentsFilter()) 

165 

166 if options.get('strip_whitespace') or options.get('reindent'): 

167 stack.enable_grouping() 

168 stack.stmtprocess.append(filters.StripWhitespaceFilter()) 

169 

170 if options.get('reindent'): 

171 stack.enable_grouping() 

172 stack.stmtprocess.append( 

173 filters.ReindentFilter( 

174 char=options['indent_char'], 

175 width=options['indent_width'], 

176 indent_after_first=options['indent_after_first'], 

177 indent_columns=options['indent_columns'], 

178 wrap_after=options['wrap_after'], 

179 comma_first=options['comma_first'], 

180 compact=options['compact'],)) 

181 

182 if options.get('reindent_aligned', False): 

183 stack.enable_grouping() 

184 stack.stmtprocess.append( 

185 filters.AlignedIndentFilter(char=options['indent_char'])) 

186 

187 if options.get('right_margin'): 

188 stack.enable_grouping() 

189 stack.stmtprocess.append( 

190 filters.RightMarginFilter(width=options['right_margin'])) 

191 

192 # Serializer 

193 if options.get('output_format'): 

194 frmt = options['output_format'] 

195 if frmt.lower() == 'php': 

196 fltr = filters.OutputPHPFilter() 

197 elif frmt.lower() == 'python': 

198 fltr = filters.OutputPythonFilter() 

199 else: 

200 fltr = None 

201 if fltr is not None: 

202 stack.postprocess.append(fltr) 

203 

204 return stack