codekingpro/portable-devtools
115k
1#2# Copyright (C) 2009-2020 the sqlparse authors and contributors3# <see AUTHORS file>4#5# This module is part of python-sqlparse and is released under6# the BSD License: https://opensource.org/licenses/BSD-3-Clause7 8import itertools9import re10from collections import deque11from contextlib import contextmanager12 13# This regular expression replaces the home-cooked parser that was here before.14# It is much faster, but requires an extra post-processing step to get the15# desired results (that are compatible with what you would expect from the16# str.splitlines() method).17#18# It matches groups of characters: newlines, quoted strings, or unquoted text,19# and splits on that basis. The post-processing step puts those back together20# into the actual lines of SQL.21SPLIT_REGEX = re.compile(r"""22(23 (?: # Start of non-capturing group24 (?:\r\n|\r|\n) | # Match any single newline, or25 [^\r\n'"]+ | # Match any character series without quotes or26 # newlines, or27 "(?:[^"\\]|\\.)*" | # Match double-quoted strings, or28 '(?:[^'\\]|\\.)*' # Match single quoted strings29 )30)31""", re.VERBOSE)32 33LINE_MATCH = re.compile(r'(\r\n|\r|\n)')34 35 36def split_unquoted_newlines(stmt):37 """Split a string on all unquoted newlines.38 39 Unlike str.splitlines(), this will ignore CR/LF/CR+LF if the requisite40 character is inside of a string."""41 text = str(stmt)42 lines = SPLIT_REGEX.split(text)43 outputlines = ['']44 for line in lines:45 if not line:46 continue47 elif LINE_MATCH.match(line):48 outputlines.append('')49 else:50 outputlines[-1] += line51 return outputlines52 53 54def remove_quotes(val):55 """Helper that removes surrounding quotes from strings."""56 if val is None:57 return58 if val[0] in ('"', "'", '`') and val[0] == val[-1]:59 val = val[1:-1]60 return val61 62 63def recurse(*cls):64 """Function decorator to help with recursion65 66 :param cls: Classes to not recurse over67 :return: function68 """69 def wrap(f):70 def wrapped_f(tlist):71 for sgroup in tlist.get_sublists():72 if not isinstance(sgroup, cls):73 wrapped_f(sgroup)74 f(tlist)75 76 return wrapped_f77 78 return wrap79 80 81def imt(token, i=None, m=None, t=None):82 """Helper function to simplify comparisons Instance, Match and TokenType83 :param token:84 :param i: Class or Tuple/List of Classes85 :param m: Tuple of TokenType & Value. Can be list of Tuple for multiple86 :param t: TokenType or Tuple/List of TokenTypes87 :return: bool88 """89 if token is None:90 return False91 if i and isinstance(token, i):92 return True93 if m:94 if isinstance(m, list):95 if any(token.match(*pattern) for pattern in m):96 return True97 elif token.match(*m):98 return True99 if t:100 if isinstance(t, list):101 if any(token.ttype in ttype for ttype in t):102 return True103 elif token.ttype in t:104 return True105 return False106 107 108def consume(iterator, n):109 """Advance the iterator n-steps ahead. If n is none, consume entirely."""110 deque(itertools.islice(iterator, n), maxlen=0)111 112 113@contextmanager114def offset(filter_, n=0):115 filter_.offset += n116 yield117 filter_.offset -= n118 119 120@contextmanager121def indent(filter_, n=1):122 filter_.indent += n123 yield124 filter_.indent -= n125 