kaqing 2.0.70__py3-none-any.whl → 2.0.71__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
adam/sql/sql_completer.py CHANGED
@@ -2,151 +2,30 @@ from typing import Callable, Iterable
2
2
  from prompt_toolkit.completion import CompleteEvent, Completer, Completion
3
3
  from prompt_toolkit.document import Document
4
4
  import sqlparse
5
- from sqlparse.sql import Statement, Token
6
- from sqlparse import tokens as T
5
+ from sqlparse.sql import Statement
7
6
 
7
+ from adam.sql.state_machine import StateMachine
8
8
  from adam.sql.term_completer import TermCompleter
9
9
 
10
- columns = TermCompleter(['id', 'x.', 'y.', 'z.'])
10
+ __all__ = [
11
+ "SqlCompleter",
12
+ ]
11
13
 
12
- def fr(*args):
13
- for arg in args:
14
- pass
14
+ DML_COMPLETER = TermCompleter(['select', 'insert', 'delete', 'update'])
15
15
 
16
16
  class SqlCompleter(Completer):
17
- # <select_statement> ::= SELECT <select_list>
18
- # FROM <table_expression>
19
- # [WHERE <search_condition>]
20
- # [<group_by_clause>]
21
- # [<having_clause>]
22
- # [<order_by_clause>]
23
- # [<limit_clause>]
24
-
25
- # <search_condition> ::= <boolean_term>
26
- # | <search_condition> OR <boolean_term>
27
-
28
- # <boolean_term> ::= <boolean_factor>
29
- # | <boolean_term> AND <boolean_factor>
30
-
31
- # <boolean_factor> ::= [NOT] <predicate>
32
- # | ([NOT] <search_condition>)
33
-
34
- # <predicate> ::= <comparison_predicate>
35
- # | <between_predicate>
36
- # | <in_predicate>
37
- # | <like_predicate>
38
- # | <null_predicate>
39
- # | <exists_predicate>
40
- # | <quantified_predicate>
41
- # | <unique_predicate>
42
- # | <match_predicate>
43
- # | <overlaps_predicate>
44
- # | <distinct_predicate>
45
- # | <member_predicate>
46
- # | <submultiset_predicate>
47
- # | <set_predicate>
48
-
49
- # <comparison_predicate> ::= <row_value_expression> <comparison_operator> <row_value_expression>
50
- # <comparison_operator> ::= '=' | '<>' | '<' | '<=' | '>' | '>='
51
-
52
- # <row_value_expression> ::= <value_expression>
53
- # | (<value_expression> [ { <comma> <value_expression> }... ])
54
-
55
- # <value_expression> ::= <numeric_value_expression>
56
- # | <string_value_expression>
57
- # | <datetime_value_expression>
58
- # | <interval_value_expression>
59
- # | <boolean_value_expression>
60
- # | <user_defined_type_value_expression>
61
- # | <reference_value_expression>
62
- # | <collection_value_expression>
63
- # | <row_value_constructor>
64
- # | <case_expression>
65
- # | <cast_expression>
66
- # | <subquery>
67
- # | NULL
68
- # | DEFAULT
69
- # | <identifier>
70
- # | <literal>
71
-
72
- # <insert_statement> ::= INSERT INTO <table_name> [ ( <column_list> ) ]
73
- # VALUES ( <value_list> )
74
- # | INSERT INTO <table_name> [ ( <column_list> ) ]
75
- # <query_expression>
76
-
77
- # <table_name> ::= <identifier>
78
-
79
- # <column_list> ::= <column_name> [ , <column_list> ]
80
-
81
- # <column_name> ::= <identifier>
82
-
83
- # <value_list> ::= <expression> [ , <value_list> ]
84
-
85
- # <query_expression> ::= SELECT <select_list> FROM <table_reference_list> [ WHERE <search_condition> ] [ GROUP BY <grouping_column_list> ] [ HAVING <search_condition> ] [ ORDER BY <sort_specification_list> ]
86
-
87
- # <update_statement> ::= UPDATE <table_name>
88
- # SET <set_clause_list>
89
- # [WHERE <search_condition>]
90
-
91
- # <set_clause_list> ::= <set_clause> { , <set_clause> }
92
-
93
- # <set_clause> ::= <column_name> = <update_value>
94
-
95
- # <update_value> ::= <expression> | NULL | DEFAULT
96
-
97
- # <search_condition> ::= <boolean_expression>
98
-
99
- # <delete_statement> ::= DELETE FROM <table_name> [ WHERE <search_condition> ]
100
-
101
- # <table_name> ::= <identifier>
102
-
103
- # <search_condition> ::= <boolean_expression>
104
-
105
- # <boolean_expression> ::= <predicate>
106
- # | <boolean_expression> AND <predicate>
107
- # | <boolean_expression> OR <predicate>
108
- # | NOT <predicate>
109
- # | ( <boolean_expression> )
110
-
111
- # <predicate> ::= <expression> <comparison_operator> <expression>
112
- # | <expression> IS NULL
113
- # | <expression> IS NOT NULL
114
- # | <expression> LIKE <pattern> [ ESCAPE <escape_character> ]
115
- # | <expression> IN ( <expression_list> )
116
- # | EXISTS ( <select_statement> )
117
- # | ... (other predicates)
118
-
119
- # <comparison_operator> ::= = | <> | != | > | < | >= | <=
120
-
121
- # <expression> ::= <literal>
122
- # | <column_name>
123
- # | <function_call>
124
- # | ( <expression> )
125
- # | <expression> <arithmetic_operator> <expression>
126
- # | ... (other expressions)
127
-
128
- # <literal> ::= <numeric_literal> | <string_literal> | <boolean_literal> | <date_literal> | ...
129
-
130
- # <column_name> ::= <identifier>
131
-
132
- # <identifier> ::= <letter> { <letter> | <digit> | _ }...
133
-
134
- # <pattern> ::= <string_literal>
135
-
136
- # <escape_character> ::= <string_literal> (single character)
137
-
138
- # <expression_list> ::= <expression> { , <expression> }...
139
17
  def __init__(self, tables: Callable[[], list[str]], dml: str = None, debug = False):
140
18
  super().__init__()
141
19
  self.dml = dml
142
20
  self.tables = tables
143
21
  self.debug = debug
144
- self.machine = self.automata()
22
+ self.machine = StateMachine(debug=self.debug)
145
23
 
146
24
  def get_completions(
147
25
  self, document: Document, complete_event: CompleteEvent
148
26
  ) -> Iterable[Completion]:
149
27
  text = document.text_before_cursor.lstrip()
28
+ state = ''
150
29
  if self.dml:
151
30
  state = f'{self.dml}_'
152
31
  text = f'{self.dml} {text}'
@@ -154,22 +33,20 @@ class SqlCompleter(Completer):
154
33
  completer: Completer = None
155
34
  stmts = sqlparse.parse(text)
156
35
  if not stmts:
157
- completer = TermCompleter(['select', 'insert', 'delete', 'update'])
36
+ completer = DML_COMPLETER
158
37
  else:
159
38
  statement: Statement = stmts[0]
160
- state = self.traverse_tokens(text, statement.tokens)
39
+ state = self.machine.traverse_tokens(statement.tokens, state)
161
40
  if self.debug:
162
41
  print('\n =>', state)
163
42
 
164
- if state == '':
165
- completer = TermCompleter(['select', 'insert', 'delete', 'update'])
43
+ if not state:
44
+ completer = DML_COMPLETER
166
45
 
167
- completers: dict[str, str] = self.machine[1]
168
- if state in completers:
46
+ if state in self.machine.suggestions:
169
47
  terms = []
170
48
 
171
- words = completers[state]
172
- for word in words.strip(' ').split(','):
49
+ for word in self.machine.suggestions[state].strip(' ').split(','):
173
50
  if word == 'tables':
174
51
  terms.extend(self.tables())
175
52
  elif word == 'single':
@@ -186,302 +63,6 @@ class SqlCompleter(Completer):
186
63
  for c in completer.get_completions(document, complete_event):
187
64
  yield c
188
65
 
189
- def automata(self):
190
- y = [
191
- ' > select > select',
192
- 'select_ > name|* > select_a ^ *',
193
- 'select_a > , > select_a_comma_',
194
- 'select_a_comma_ > name|* > select_a ^ *',
195
- 'select_a_ > from > select_from ^ from',
196
- 'select_from_ > name > select_from_x ^ (select,tables',
197
- '- > { > select_from_x_lp_',
198
- 'select_from_x_lp_ > select > select',
199
- 'select_from_x > , > select_from_x_comma_',
200
- '- > } > select_from_x_rp_',
201
- 'select_from_x_rp__ > as > select_from_x_as ^ as',
202
- 'select_from_x_comma_ > name > select_from_x ^ tables',
203
- 'select_from_x_ ^ as,where,inner join,left outer join,right outer join,full outer join,group by,limit',
204
- 'select_from_x_as_x_ > , > select_from_x_comma_ ^ where,inner join,left outer join,right outer join,full outer join,group by,limit',
205
- '- > as > select_from_x_as',
206
- '- > where > select_where',
207
- '- > limit > select_where_sc_limit',
208
- '- > group > select_group',
209
- '- > group by > select_group_by',
210
- '- > inner > select_from_x_inner',
211
- '- > inner join > select_join',
212
- '- > left > select_from_x_left',
213
- '- > left join > select_join',
214
- '- > left outer join > select_join',
215
- '- > right > select_from_x_right',
216
- '- > right join > select_join',
217
- '- > right outer join > select_join',
218
- '- > full > select_from_x_full',
219
- '- > full outer join > select_join',
220
- 'select_from_x_as_ > name > select_from_x_as_x ^ x,y,z',
221
- 'select_from_x_as_x > , > select_from_x_as_x_comma_',
222
- '- > } > select_where_sc_re_',
223
- 'select_from_x_as_x_comma_ > name > select_from_x ^ tables',
224
- 'select_where_ > name > select_where_a ^ id,x.,y.,z.',
225
- 'select_where_a > comparison > select_where_a_op ^ =,<,<=,>,>=,<>,like,not,in',
226
- 'select_where_a_ > comparison > select_where_a_op ^ =,<,<=,>,>=,<>,like,not,in',
227
- '- > not > select_where_a_not',
228
- '- > in > select_where_a_in',
229
- 'select_where_a_not_ > comparison > select_where_a_not_op ^ like,in',
230
- '- > in > select_where_a_in',
231
- 'select_where_a_in > ( > select_where_a_in_lp_ ^ (',
232
- 'select_where_a_in_lp_ > name|single|num > select_where_a_in_lp_a ^ single,select',
233
- '- > select > select_where_a_in_lp_select',
234
- 'select_where_a_in_lp_select_ > name > select_a ^ id',
235
- 'select_where_a_in_lp_a > , > select_where_a_in_lp_a_comma_ ^ comma,)',
236
- '- > ) > select_where_sc',
237
- 'select_where_a_in_lp_a_comma_ > name|single|num > select_where_a_in_lp_a ^ single',
238
- 'select_where_a_not_op > name|single|num > select_where_sc ^ single',
239
- 'select_where_a_op > name|single|num > select_where_sc ^ single',
240
- 'select_where_sc > ) > select_where_sc_rp_',
241
- 'select_where_sc > } > select_where_sc_re_',
242
- 'select_where_sc_re__ > as > select_from_x_as ^ as',
243
- 'select_where_sc_rp_ > } > select_where_sc_re_',
244
- 'select_where_sc_rp__ > as > select_from_x_as ^ and,or,group by,limit',
245
- '- > and|or > select_where',
246
- '- > group > select_group',
247
- '- > group by > select_group_by',
248
- '- > limit > select_where_sc_limit',
249
- '- > } > select_where_sc_re_',
250
- 'select_where_sc_ > and|or > select_where ^ and,or,group by,limit',
251
- '- > group > select_group',
252
- '- > group by > select_group_by',
253
- '- > limit > select_where_sc_limit',
254
- 'select_group_ > by > select_group_by ^ by',
255
- 'select_group_by_ > name > select_group_by_a ^ id,x.,y.,z.',
256
- 'select_group_by_a > , > select_group_by_a_comma_',
257
- '- > } > select_where_sc_re_',
258
- 'select_group_by_a_comma_ > name > select_group_by_a ^ id,x.,y.,z.',
259
- 'select_group_by_a_ > limit > select_where_sc_limit ^ limit',
260
- 'select_where_sc_limit_ > num > select_where_sc_limit_num ^ 1',
261
- 'select_where_sc_limit_num > ) > select_where_sc_limit_num_rp_',
262
- 'select_where_sc_limit_num_rp__ > as > select_from_x_as ^ as',
263
- 'select_where_x_inner_ > join > select_join',
264
- 'select_join_ > name > select_x_join_y ^ tables',
265
- 'select_from_x_left_ > join > select_join ^ outer join',
266
- '- > outer > select_from_x_left_outer',
267
- 'select_from_x_left_outer_ > join > select_join ^ join',
268
- 'select_from_x_right_ > join > select_join ^ outer join',
269
- '- > outer > select_from_x_right_outer',
270
- 'select_from_x_right_outer_ > join > select_join ^ join',
271
- 'select_from_x_full_ > join > select_join ^ outer join',
272
- '- > outer > select_from_x_full_outer',
273
- 'select_from_x_full_outer_ > join > select_join ^ join',
274
- 'select_x_join_y_ > as > select_x_join_y_as ^ as,on',
275
- '- > on > select_x_join_y_on ^ as,on',
276
- 'select_x_join_y_as_ > name > select_x_join_y_as_y ^ x,y,z',
277
- 'select_x_join_y_as_y_ > on > select_x_join_y_on ^ on',
278
- 'select_x_join_y_on_ > name > select_x_join_y_on_a ^ id,x.,y.,z.',
279
- 'select_x_join_y_on_a > comparison > select_x_join_y_on_a_op ^ =',
280
- 'select_x_join_y_on_a_op > name > select_x_join_y_on_a_op_b ^ id,x.,y.,z.',
281
- 'select_x_join_y_on_a_op_b > _ > select_from_x_as_x_',
282
- '- > } > select_where_sc_re_',
283
-
284
-
285
- ' > insert > insert',
286
- 'insert_ > into > insert_into ^ into',
287
- 'insert_into_ > name > insert_into_x ^ tables',
288
- 'insert_into_x > ( > insert_into_x_lp_',
289
- 'insert_into_x_ > ( > insert_into_x_lp_ ^ (,values(',
290
- '- > values > insert_values',
291
- 'insert_into_x_lp_ > name > insert_into_x_lp_a ^ id',
292
- 'insert_into_x_lp_a > , > insert_into_x_lp_a_comma_',
293
- '- > ) > insert_into_x_lp_a_rp_',
294
- 'insert_into_x_lp_a_comma_ > name > insert_into_x_lp_a ^ id',
295
- 'insert_into_x_lp_a_rp__ > values > insert_values ^ values(,select',
296
- '- > select > select',
297
- 'insert_values > ( > insert_values_lp_',
298
- 'insert_values_lp_ > name|single|num > insert_values_lp_v ^ single',
299
- 'insert_values_lp_v > , > insert_values_lp_v_comma_',
300
- 'insert_values_lp_v_comma_ > name|single|num > insert_values_lp_v',
301
-
302
-
303
- ' > update > update',
304
- 'update_ > name > update_x ^ tables',
305
- 'update_x_ > set > update_set ^ set',
306
- 'update_set_ > name > update_set_a ^ id',
307
- 'update_set_a > comparison > update_set_a_op',
308
- 'update_set_a_op > name|single|num > update_set_sc ^ single',
309
- 'update_set_sc > , > update_set_sc_comma_',
310
- 'update_set_sc_comma_ > name > update_set_a ^ id',
311
- 'update_set_sc_ > , > update_set_sc_comma_ ^ where',
312
- '- > where > update_where',
313
- 'update_where_ > name > update_where_a ^ id',
314
- 'update_where_a > comparison > update_where_a_op',
315
- 'update_where_a_ > comparison > update_where_a_op ^ =,<,<=,>,>=,<>,like,not,in',
316
- '- > not > update_where_a_not',
317
- '- > in > update_where_a_in',
318
- 'update_where_a_not_ > comparison > update_where_a_not_op ^ like,in',
319
- '- > in > update_where_a_in',
320
- 'update_where_a_in > ( > update_where_a_in_lp_ ^ (',
321
- 'update_where_a_in_lp_ > name|single|num > update_where_a_in_lp_a ^ single,select',
322
- '- > select > update_where_a_in_lp_select',
323
- 'update_where_a_in_lp_select_ > name > select_a ^ id',
324
- 'update_where_a_in_lp_a > , > update_where_a_in_lp_a_comma_ ^ comma,)',
325
- '- > ) > update_where_sc',
326
- 'update_where_a_in_lp_a_comma_ > name|single|num > update_where_a_in_lp_a ^ single',
327
- 'update_where_a_not_op > name|single|num > update_where_sc ^ single',
328
- 'update_where_a_op > name|single|num > update_where_sc ^ single',
329
- 'update_where_sc_ > and|or > update_where ^ and,or',
330
-
331
-
332
- ' > delete > delete',
333
- 'delete_ > from > delete_from ^ from',
334
- 'delete_from_ > name > delete_from_x ^ tables',
335
- 'delete_from_x_ > where > update_where ^ where',
336
- ]
337
-
338
- def add_whitespace_transition(from_s: str):
339
- # add whitespace transition if a state with trailing whitespace is found from from states, for example, select > _ > select_
340
- if from_s.endswith('_') and not from_s.endswith('_comma_') and not from_s.endswith('_lp_') and not from_s.endswith('_rp_'):
341
- if self.debug:
342
- print(f'{from_s[:-1]} > _ = {to_s}')
343
- machine[f'{from_s[:-1]} > _'] = from_s
344
-
345
- machine: dict[str, str] = {}
346
- completers: dict[str, str] = {}
347
-
348
- from_ss_to_add = []
349
- from_ss = ['']
350
- token = None
351
- tokens = []
352
- to_s = None
353
- words: str = None
354
- for l in y:
355
- t_and_w = l.split('^')
356
- if len(t_and_w) > 1:
357
- words = t_and_w[1]
358
- else:
359
- words = None
360
-
361
- tks = t_and_w[0].strip(' ').split('>')
362
- if l.startswith('-'):
363
- token = tks[1].strip(' ')
364
- if len(tks) > 2:
365
- to_s = tks[2].strip(' ')
366
- for from_s in from_ss:
367
- tokens = [token]
368
- if '|' in token:
369
- tokens = token.strip(' ').split('|')
370
-
371
- for t in tokens:
372
- if self.debug:
373
- print(f'{from_s} > {t} = {to_s}')
374
- machine[f'{from_s} > {t}'] = to_s
375
- else:
376
- if words:
377
- completers[tks[0].strip(' ')] = words
378
-
379
- if len(tks) == 1:
380
- from_s = tks[0].strip(' ')
381
- add_whitespace_transition(from_s)
382
- from_ss_to_add.append(f'{from_s}')
383
- continue
384
-
385
- from_ss = []
386
- from_ss.extend(from_ss_to_add)
387
- from_ss_to_add = []
388
- from_ss.append(tks[0].strip(' '))
389
- for from_s in from_ss:
390
- add_whitespace_transition(from_s)
391
- token = tks[1].strip(' ')
392
- tokens = [token]
393
- if len(tks) > 2:
394
- to_s = tks[2].strip(' ')
395
-
396
- if '|' in token:
397
- tokens = token.split('|')
398
-
399
- for t in tokens:
400
- if self.debug:
401
- print(f'{from_s} > {t} = {to_s}')
402
- machine[f'{from_s} > {t}'] = to_s
403
-
404
- return (machine, completers)
405
-
406
- def traverse_tokens(self, text: str, tokens: list[Token], state: str = '', indent=0, lp_level = 0, lp_levels_to_match: set = set()):
407
- keywords = [
408
- 'select', 'from', 'as', 'not', 'in', 'where',
409
- 'and', 'or', 'group', 'by', 'group by', 'limit',
410
- 'inner join', 'on', 'left', 'right', 'full', 'outer', 'left outer join',
411
- 'left join', 'right outer join', 'right join', 'full join', 'full outer join',
412
-
413
- 'insert', 'into', 'values',
414
-
415
- 'update', 'where', 'set',
416
-
417
- 'delete'
418
- ]
419
-
420
- def is_opening_embrace():
421
- if f'{state} > ' + '{' in self.machine[0]:
422
- lp_levels_to_match.add(lp_level)
423
- return '{'
424
-
425
- return '('
426
-
427
- def is_closing_embrace():
428
- if f'{state} > ' + '}' in self.machine[0] and lp_level in lp_levels_to_match:
429
- lp_levels_to_match.remove(lp_level)
430
- return '}'
431
-
432
- return ')'
433
-
434
- for token in tokens:
435
- if self.debug:
436
- if token.ttype == T.Whitespace:
437
- print('_ ', end='')
438
- elif token.ttype in [T.DML, T.Wildcard, T.Punctuation]:
439
- print(f'{token.value} ', end='')
440
- elif token.ttype:
441
- tks = str(token.ttype).split('.')
442
- typ = tks[len(tks) - 1]
443
- if ' ' in token.value:
444
- print(f'"{token.value}:{typ}" ', end='')
445
- else:
446
- print(f'{token.value}:{typ} ', end='')
447
- # print(" " * indent + f"Token: {token.value}, Type: {token.ttype}@{token.ttype.__class__}")
448
-
449
- if token.is_group:
450
- state = self.traverse_tokens(text, token.tokens, state, indent + 1, lp_level)
451
- else:
452
- it = ''
453
- if (t := token.value.lower()) in keywords:
454
- it = t
455
- elif token.ttype == T.Text.Whitespace:
456
- it = '_'
457
- elif token.ttype == T.Name:
458
- it = 'name'
459
- elif token.ttype == T.Literal.String.Single:
460
- it = 'single'
461
- elif token.ttype in [T.Literal.Number.Integer, T.Literal.Number.Float]:
462
- it = 'num'
463
- elif token.ttype == T.Wildcard:
464
- it = '*'
465
- elif token.ttype == T.Punctuation:
466
- if token.value == ',':
467
- it = ','
468
- elif token.value == '(':
469
- it = is_opening_embrace()
470
- lp_level += 1
471
- elif token.value == ')':
472
- lp_level -= 1
473
- it = is_closing_embrace()
474
-
475
- elif token.ttype == T.Operator.Comparison:
476
- it = 'comparison'
477
-
478
- try:
479
- state = self.machine[0][f'{state} > {it}']
480
- except:
481
- pass
482
-
483
- return state
484
-
485
66
  def completions(table_names: Callable[[], list[str]]):
486
67
  return {
487
68
  'delete': SqlCompleter(table_names, 'delete'),
@@ -0,0 +1,444 @@
1
+ # <select_statement> ::= SELECT <select_list>
2
+ # FROM <table_expression>
3
+ # [WHERE <search_condition>]
4
+ # [<group_by_clause>]
5
+ # [<having_clause>]
6
+ # [<order_by_clause>]
7
+ # [<limit_clause>]
8
+
9
+ # <search_condition> ::= <boolean_term>
10
+ # | <search_condition> OR <boolean_term>
11
+
12
+ # <boolean_term> ::= <boolean_factor>
13
+ # | <boolean_term> AND <boolean_factor>
14
+
15
+ # <boolean_factor> ::= [NOT] <predicate>
16
+ # | ([NOT] <search_condition>)
17
+
18
+ # <predicate> ::= <comparison_predicate>
19
+ # | <between_predicate>
20
+ # | <in_predicate>
21
+ # | <like_predicate>
22
+ # | <null_predicate>
23
+ # | <exists_predicate>
24
+ # | <quantified_predicate>
25
+ # | <unique_predicate>
26
+ # | <match_predicate>
27
+ # | <overlaps_predicate>
28
+ # | <distinct_predicate>
29
+ # | <member_predicate>
30
+ # | <submultiset_predicate>
31
+ # | <set_predicate>
32
+
33
+ # <comparison_predicate> ::= <row_value_expression> <comparison_operator> <row_value_expression>
34
+ # <comparison_operator> ::= '=' | '<>' | '<' | '<=' | '>' | '>='
35
+
36
+ # <row_value_expression> ::= <value_expression>
37
+ # | (<value_expression> [ { <comma> <value_expression> }... ])
38
+
39
+ # <value_expression> ::= <numeric_value_expression>
40
+ # | <string_value_expression>
41
+ # | <datetime_value_expression>
42
+ # | <interval_value_expression>
43
+ # | <boolean_value_expression>
44
+ # | <user_defined_type_value_expression>
45
+ # | <reference_value_expression>
46
+ # | <collection_value_expression>
47
+ # | <row_value_constructor>
48
+ # | <case_expression>
49
+ # | <cast_expression>
50
+ # | <subquery>
51
+ # | NULL
52
+ # | DEFAULT
53
+ # | <identifier>
54
+ # | <literal>
55
+
56
+ # <insert_statement> ::= INSERT INTO <table_name> [ ( <column_list> ) ]
57
+ # VALUES ( <value_list> )
58
+ # | INSERT INTO <table_name> [ ( <column_list> ) ]
59
+ # <query_expression>
60
+
61
+ # <table_name> ::= <identifier>
62
+
63
+ # <column_list> ::= <column_name> [ , <column_list> ]
64
+
65
+ # <column_name> ::= <identifier>
66
+
67
+ # <value_list> ::= <expression> [ , <value_list> ]
68
+
69
+ # <query_expression> ::= SELECT <select_list> FROM <table_reference_list> [ WHERE <search_condition> ] [ GROUP BY <grouping_column_list> ] [ HAVING <search_condition> ] [ ORDER BY <sort_specification_list> ]
70
+
71
+ # <update_statement> ::= UPDATE <table_name>
72
+ # SET <set_clause_list>
73
+ # [WHERE <search_condition>]
74
+
75
+ # <set_clause_list> ::= <set_clause> { , <set_clause> }
76
+
77
+ # <set_clause> ::= <column_name> = <update_value>
78
+
79
+ # <update_value> ::= <expression> | NULL | DEFAULT
80
+
81
+ # <search_condition> ::= <boolean_expression>
82
+
83
+ # <delete_statement> ::= DELETE FROM <table_name> [ WHERE <search_condition> ]
84
+
85
+ # <table_name> ::= <identifier>
86
+
87
+ # <search_condition> ::= <boolean_expression>
88
+
89
+ # <boolean_expression> ::= <predicate>
90
+ # | <boolean_expression> AND <predicate>
91
+ # | <boolean_expression> OR <predicate>
92
+ # | NOT <predicate>
93
+ # | ( <boolean_expression> )
94
+
95
+ # <predicate> ::= <expression> <comparison_operator> <expression>
96
+ # | <expression> IS NULL
97
+ # | <expression> IS NOT NULL
98
+ # | <expression> LIKE <pattern> [ ESCAPE <escape_character> ]
99
+ # | <expression> IN ( <expression_list> )
100
+ # | EXISTS ( <select_statement> )
101
+ # | ... (other predicates)
102
+
103
+ # <comparison_operator> ::= = | <> | != | > | < | >= | <=
104
+
105
+ # <expression> ::= <literal>
106
+ # | <column_name>
107
+ # | <function_call>
108
+ # | ( <expression> )
109
+ # | <expression> <arithmetic_operator> <expression>
110
+ # | ... (other expressions)
111
+
112
+ # <literal> ::= <numeric_literal> | <string_literal> | <boolean_literal> | <date_literal> | ...
113
+
114
+ # <column_name> ::= <identifier>
115
+
116
+ # <identifier> ::= <letter> { <letter> | <digit> | _ }...
117
+
118
+ # <pattern> ::= <string_literal>
119
+
120
+ # <escape_character> ::= <string_literal> (single character)
121
+
122
+ # <expression_list> ::= <expression> { , <expression> }...
123
+
124
+ from sqlparse.sql import Token
125
+ from sqlparse import tokens as T
126
+
127
+ __all__ = [
128
+ "StateMachine",
129
+ ]
130
+
131
+ SPEC = [
132
+ ' > select > select',
133
+ 'select_ > name|* > select_a ^ *',
134
+ 'select_a > , > select_a_comma_',
135
+ 'select_a_comma_ > name|* > select_a ^ *',
136
+ 'select_a_ > from > select_from ^ from',
137
+ 'select_from_ > name > select_from_x ^ (select,tables',
138
+ '- > { > select_from_x_lp_',
139
+ 'select_from_x_lp_ > select > select',
140
+ 'select_from_x > , > select_from_x_comma_',
141
+ '- > } > select_from_x_rp_',
142
+ '- > ] > select_from_x_rb_',
143
+ 'select_from_x_rp__ > as > select_from_x_as ^ as',
144
+ 'select_from_x_rb__ > and|or > select_where_ ^ and,or,group by,limit',
145
+ '- > group > select_group',
146
+ '- > group by > select_group_by',
147
+ '- > limit > select_where_sc_limit',
148
+ 'select_from_x_comma_ > name > select_from_x ^ tables',
149
+ 'select_from_x_ ^ as,where,inner join,left outer join,right outer join,full outer join,group by,limit',
150
+ 'select_from_x_as_x_ > , > select_from_x_comma_ ^ where,inner join,left outer join,right outer join,full outer join,group by,limit',
151
+ '- > as > select_from_x_as',
152
+ '- > where > select_where',
153
+ '- > limit > select_where_sc_limit',
154
+ '- > group > select_group',
155
+ '- > group by > select_group_by',
156
+ '- > inner > select_from_x_inner',
157
+ '- > inner join > select_join',
158
+ '- > left > select_from_x_left',
159
+ '- > left join > select_join',
160
+ '- > left outer join > select_join',
161
+ '- > right > select_from_x_right',
162
+ '- > right join > select_join',
163
+ '- > right outer join > select_join',
164
+ '- > full > select_from_x_full',
165
+ '- > full outer join > select_join',
166
+ 'select_from_x_as_ > name > select_from_x_as_x ^ x,y,z',
167
+ 'select_from_x_as_x > , > select_from_x_as_x_comma_',
168
+ '- > } > select_where_sc_re_',
169
+ 'select_from_x_as_x_comma_ > name > select_from_x ^ tables',
170
+ 'select_where_ > name > select_where_a ^ id,x.,y.,z.',
171
+ 'select_where_a > comparison > select_where_a_op ^ =,<,<=,>,>=,<>,like,not,in',
172
+ 'select_where_a_ > comparison > select_where_a_op ^ =,<,<=,>,>=,<>,like,not,in',
173
+ '- > not > select_where_a_not',
174
+ '- > in > select_where_a_in',
175
+ 'select_where_a_not_ > comparison > select_where_a_not_op ^ like,in',
176
+ '- > in > select_where_a_in',
177
+ 'select_where_a_in > [ > select_where_a_in_lp_ ^ (',
178
+ 'select_where_a_in_lp_ > name|single|num > select_where_a_in_lp_a ^ single,select',
179
+ '- > select > select_where_a_in_lp_select',
180
+ 'select_where_a_in_lp_select_ > name > select_a ^ id',
181
+ 'select_where_a_in_lp_a > , > select_where_a_in_lp_a_comma_ ^ comma,)',
182
+ '- > ] > select_where_sc',
183
+ 'select_where_a_in_lp_a_comma_ > name|single|num > select_where_a_in_lp_a ^ single',
184
+ 'select_where_a_not_op > name|single|num > select_where_sc ^ single',
185
+ 'select_where_a_op > name|single|num > select_where_sc ^ single',
186
+ 'select_where_sc > ) > select_where_sc_rp_',
187
+ 'select_where_sc > } > select_where_sc_re_',
188
+ 'select_where_sc_re__ > as > select_from_x_as ^ as',
189
+ 'select_where_sc_rp_ > } > select_where_sc_re_',
190
+ 'select_where_sc_rp__ > as > select_from_x_as ^ and,or,group by,limit',
191
+ '- > and|or > select_where',
192
+ '- > group > select_group',
193
+ '- > group by > select_group_by',
194
+ '- > limit > select_where_sc_limit',
195
+ '- > } > select_where_sc_re_',
196
+ 'select_where_sc_ > and|or > select_where ^ and,or,group by,limit',
197
+ '- > group > select_group',
198
+ '- > group by > select_group_by',
199
+ '- > limit > select_where_sc_limit',
200
+ 'select_group_ > by > select_group_by ^ by',
201
+ 'select_group_by_ > name > select_group_by_a ^ id,x.,y.,z.',
202
+ 'select_group_by_a > , > select_group_by_a_comma_',
203
+ '- > } > select_where_sc_re_',
204
+ 'select_group_by_a_comma_ > name > select_group_by_a ^ id,x.,y.,z.',
205
+ 'select_group_by_a_ > limit > select_where_sc_limit ^ limit',
206
+ 'select_where_sc_limit_ > num > select_where_sc_limit_num ^ 1',
207
+ 'select_where_sc_limit_num > ) > select_where_sc_limit_num_rp_',
208
+ 'select_where_sc_limit_num_rp__ > as > select_from_x_as ^ as',
209
+ 'select_where_x_inner_ > join > select_join',
210
+ 'select_join_ > name > select_x_join_y ^ tables',
211
+ 'select_from_x_left_ > join > select_join ^ outer join',
212
+ '- > outer > select_from_x_left_outer',
213
+ 'select_from_x_left_outer_ > join > select_join ^ join',
214
+ 'select_from_x_right_ > join > select_join ^ outer join',
215
+ '- > outer > select_from_x_right_outer',
216
+ 'select_from_x_right_outer_ > join > select_join ^ join',
217
+ 'select_from_x_full_ > join > select_join ^ outer join',
218
+ '- > outer > select_from_x_full_outer',
219
+ 'select_from_x_full_outer_ > join > select_join ^ join',
220
+ 'select_x_join_y_ > as > select_x_join_y_as ^ as,on',
221
+ '- > on > select_x_join_y_on ^ as,on',
222
+ 'select_x_join_y_as_ > name > select_x_join_y_as_y ^ x,y,z',
223
+ 'select_x_join_y_as_y_ > on > select_x_join_y_on ^ on',
224
+ 'select_x_join_y_on_ > name > select_x_join_y_on_a ^ id,x.,y.,z.',
225
+ 'select_x_join_y_on_a > comparison > select_x_join_y_on_a_op ^ =',
226
+ 'select_x_join_y_on_a_op > name > select_x_join_y_on_a_op_b ^ id,x.,y.,z.',
227
+ 'select_x_join_y_on_a_op_b > _ > select_from_x_as_x_',
228
+ '- > } > select_where_sc_re_',
229
+
230
+
231
+ ' > insert > insert',
232
+ 'insert_ > into > insert_into ^ into',
233
+ 'insert_into_ > name > insert_into_x ^ tables',
234
+ 'insert_into_x > ( > insert_into_x_lp_',
235
+ 'insert_into_x_ > ( > insert_into_x_lp_ ^ (,values(',
236
+ '- > values > insert_values',
237
+ 'insert_into_x_lp_ > name > insert_into_x_lp_a ^ id',
238
+ 'insert_into_x_lp_a > , > insert_into_x_lp_a_comma_',
239
+ '- > ) > insert_into_x_lp_a_rp_',
240
+ 'insert_into_x_lp_a_comma_ > name > insert_into_x_lp_a ^ id',
241
+ 'insert_into_x_lp_a_rp__ > values > insert_values ^ values(,select',
242
+ '- > select > select',
243
+ 'insert_values > ( > insert_values_lp_',
244
+ 'insert_values_lp_ > name|single|num > insert_values_lp_v ^ single',
245
+ 'insert_values_lp_v > , > insert_values_lp_v_comma_',
246
+ 'insert_values_lp_v_comma_ > name|single|num > insert_values_lp_v',
247
+
248
+
249
+ ' > update > update',
250
+ 'update_ > name > update_x ^ tables',
251
+ 'update_x_ > set > update_set ^ set',
252
+ 'update_set_ > name > update_set_a ^ id',
253
+ 'update_set_a > comparison > update_set_a_op',
254
+ 'update_set_a_op > name|single|num > update_set_sc ^ single',
255
+ 'update_set_sc > , > update_set_sc_comma_',
256
+ 'update_set_sc_comma_ > name > update_set_a ^ id',
257
+ 'update_set_sc_ > , > update_set_sc_comma_ ^ where',
258
+ '- > where > update_where',
259
+ 'update_where_ > name > update_where_a ^ id',
260
+ 'update_where_a > comparison > update_where_a_op',
261
+ 'update_where_a_ > comparison > update_where_a_op ^ =,<,<=,>,>=,<>,like,not,in',
262
+ '- > not > update_where_a_not',
263
+ '- > in > update_where_a_in',
264
+ 'update_where_a_not_ > comparison > update_where_a_not_op ^ like,in',
265
+ '- > in > update_where_a_in',
266
+ 'update_where_a_in > ( > update_where_a_in_lp_ ^ (',
267
+ 'update_where_a_in_lp_ > name|single|num > update_where_a_in_lp_a ^ single,select',
268
+ '- > select > update_where_a_in_lp_select',
269
+ 'update_where_a_in_lp_select_ > name > select_a ^ id',
270
+ 'update_where_a_in_lp_a > , > update_where_a_in_lp_a_comma_ ^ comma,)',
271
+ '- > ) > update_where_sc',
272
+ 'update_where_a_in_lp_a_comma_ > name|single|num > update_where_a_in_lp_a ^ single',
273
+ 'update_where_a_not_op > name|single|num > update_where_sc ^ single',
274
+ 'update_where_a_op > name|single|num > update_where_sc ^ single',
275
+ 'update_where_sc_ > and|or > update_where ^ and,or',
276
+
277
+
278
+ ' > delete > delete',
279
+ 'delete_ > from > delete_from ^ from',
280
+ 'delete_from_ > name > delete_from_x ^ tables',
281
+ 'delete_from_x_ > where > update_where ^ where',
282
+ ]
283
+
284
+ KEYWORDS = [
285
+ 'select', 'from', 'as', 'not', 'in', 'where',
286
+ 'and', 'or', 'group', 'by', 'group by', 'limit',
287
+ 'inner join', 'on', 'left', 'right', 'full', 'outer', 'left outer join',
288
+ 'left join', 'right outer join', 'right join', 'full join', 'full outer join',
289
+
290
+ 'insert', 'into', 'values',
291
+
292
+ 'update', 'where', 'set',
293
+
294
+ 'delete'
295
+ ]
296
+
297
+ class StateMachine:
298
+ def __init__(self, indent=0, lp_level = 0, le_levels_to_match: set = set(), lb_levels_to_match: set = set(), debug = False):
299
+ self.states: dict[str, str] = {}
300
+ self.suggestions: dict[str, str] = {}
301
+
302
+ def add_whitespace_transition(from_s: str):
303
+ # add whitespace transition if a state with trailing whitespace is found from from states, for example, select > _ > select_
304
+ if from_s.endswith('_') and not from_s.endswith('_comma_') and not from_s.endswith('_lp_') and not from_s.endswith('_rp_'):
305
+ if self.debug:
306
+ print(f'{from_s[:-1]} > _ = {to_s}')
307
+ self.states[f'{from_s[:-1]} > _'] = from_s
308
+
309
+ self.indent = indent
310
+ self.lp_level = lp_level
311
+ self.le_levels_to_match = le_levels_to_match
312
+ self.lb_levels_to_match = lb_levels_to_match
313
+ self.debug = debug
314
+
315
+ from_ss_to_add = []
316
+ from_ss = ['']
317
+ token = None
318
+ tokens = []
319
+ to_s = None
320
+ words: str = None
321
+ for l in SPEC:
322
+ t_and_w = l.split('^')
323
+ if len(t_and_w) > 1:
324
+ words = t_and_w[1]
325
+ else:
326
+ words = None
327
+
328
+ tks = t_and_w[0].strip(' ').split('>')
329
+ if l.startswith('-'):
330
+ token = tks[1].strip(' ')
331
+ if len(tks) > 2:
332
+ to_s = tks[2].strip(' ')
333
+ for from_s in from_ss:
334
+ tokens = [token]
335
+ if '|' in token:
336
+ tokens = token.strip(' ').split('|')
337
+
338
+ for t in tokens:
339
+ if self.debug:
340
+ print(f'{from_s} > {t} = {to_s}')
341
+ self.states[f'{from_s} > {t}'] = to_s
342
+ else:
343
+ if words:
344
+ self.suggestions[tks[0].strip(' ')] = words
345
+
346
+ if len(tks) == 1:
347
+ from_s = tks[0].strip(' ')
348
+ add_whitespace_transition(from_s)
349
+ from_ss_to_add.append(f'{from_s}')
350
+ continue
351
+
352
+ from_ss = []
353
+ from_ss.extend(from_ss_to_add)
354
+ from_ss_to_add = []
355
+ from_ss.append(tks[0].strip(' '))
356
+ for from_s in from_ss:
357
+ add_whitespace_transition(from_s)
358
+ token = tks[1].strip(' ')
359
+ tokens = [token]
360
+ if len(tks) > 2:
361
+ to_s = tks[2].strip(' ')
362
+
363
+ if '|' in token:
364
+ tokens = token.split('|')
365
+
366
+ for t in tokens:
367
+ if self.debug:
368
+ print(f'{from_s} > {t} = {to_s}')
369
+ self.states[f'{from_s} > {t}'] = to_s
370
+
371
+ def traverse_tokens(self, tokens: list[Token], state: str = ''):
372
+ def is_opening_embrace():
373
+ if f'{state} > ' + '{' in self.states:
374
+ self.le_levels_to_match.add(self.lp_level)
375
+ return '{'
376
+ elif f'{state} > ' + '[' in self.states:
377
+ self.lb_levels_to_match.add(self.lp_level)
378
+ return '['
379
+
380
+ return '('
381
+
382
+ def is_closing_embrace():
383
+ if f'{state} > ' + '}' in self.states and self.lp_level in self.le_levels_to_match:
384
+ self.le_levels_to_match.remove(self.lp_level)
385
+ return '}'
386
+ elif f'{state} > ' + ']' in self.states and self.lp_level in self.lb_levels_to_match:
387
+ self.lb_levels_to_match.remove(self.lp_level)
388
+ return ']'
389
+
390
+ return ')'
391
+
392
+ for token in tokens:
393
+ if self.debug:
394
+ if token.ttype == T.Whitespace:
395
+ print('_ ', end='')
396
+ elif token.ttype in [T.DML, T.Wildcard, T.Punctuation]:
397
+ print(f'{token.value} ', end='')
398
+ elif token.ttype:
399
+ tks = str(token.ttype).split('.')
400
+ typ = tks[len(tks) - 1]
401
+ if ' ' in token.value:
402
+ print(f'"{token.value}:{typ}" ', end='')
403
+ else:
404
+ print(f'{token.value}:{typ} ', end='')
405
+ # print(" " * self.indent + f"Token: {token.value}, Type: {token.ttype}@{token.ttype.__class__}")
406
+
407
+ if token.is_group:
408
+ state = self.traverse_tokens(token.tokens, state)
409
+ else:
410
+ it = ''
411
+ if (t := token.value.lower()) in KEYWORDS:
412
+ it = t
413
+ elif token.ttype == T.Text.Whitespace:
414
+ it = '_'
415
+ elif token.ttype == T.Name:
416
+ it = 'name'
417
+ elif token.ttype == T.Literal.String.Single:
418
+ it = 'single'
419
+ elif token.ttype in [T.Literal.Number.Integer, T.Literal.Number.Float]:
420
+ it = 'num'
421
+ elif token.ttype == T.Wildcard:
422
+ it = '*'
423
+ elif token.ttype == T.Punctuation:
424
+ if token.value == ',':
425
+ it = ','
426
+ elif token.value == '(':
427
+ it = is_opening_embrace()
428
+ self.lp_level += 1
429
+ elif token.value == ')':
430
+ self.lp_level -= 1
431
+ it = is_closing_embrace()
432
+
433
+ elif token.ttype == T.Operator.Comparison:
434
+ it = 'comparison'
435
+
436
+ try:
437
+ # print(f'{state} > {it} > ', end='')
438
+ state = self.states[f'{state} > {it}']
439
+ # print(state)
440
+ except:
441
+ pass
442
+ # print('error')
443
+
444
+ return state
adam/version.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- __version__ = "2.0.70" #: the working version
4
+ __version__ = "2.0.71" #: the working version
5
5
  __release__ = "1.0.0" #: the release version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.70
3
+ Version: 2.0.71
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -14,7 +14,7 @@ adam/repl_commands.py,sha256=WA90Rl27Juctzr3U3kfCDk5N-oYMKlfWbZeafUgk7k0,4723
14
14
  adam/repl_session.py,sha256=uIogcvWBh7wd8QQ-p_JgLsyJ8YJgINw5vOd6JIsd7Vo,472
15
15
  adam/repl_state.py,sha256=nZO5CucSIGz68f4JreadGphRzMXPUzkTn-4XcoJJOug,8643
16
16
  adam/utils.py,sha256=2DoWsrcaioFFH0-RjT30qelVRPUJqCGTfz_ucfE7F8g,7406
17
- adam/version.py,sha256=yckbK4TX1cs1x8SSakRP16TVFCz-kWBTek3kfgTkIHA,139
17
+ adam/version.py,sha256=qPkOjYvtKhYQ3aGe7beaUUKB7yZ034998K9faumBULU,139
18
18
  adam/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  adam/checks/check.py,sha256=Qopr3huYcMu2bzQgb99dEUYjFzkjKHRI76S6KA9b9Rk,702
20
20
  adam/checks/check_context.py,sha256=FEHkQ32jY1EDopQ2uYWqy9v7aEEX1orLpJWhopwAlh4,402
@@ -164,7 +164,8 @@ adam/k8s_utils/services.py,sha256=EOJJGACVbbRvu5T3rMKqIJqgYic1_MSJ17EA0TJ6UOk,31
164
164
  adam/k8s_utils/statefulsets.py,sha256=5g7KxGRHgEewT8rnZneDTaJDylUf-dHH2edWJEoorr8,4667
165
165
  adam/k8s_utils/volumes.py,sha256=RIBmlOSWM3V3QVXLCFT0owVOyh4rGG1ETp521a-6ndo,1137
166
166
  adam/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
- adam/sql/sql_completer.py,sha256=VQfSPgNenkzIPKdER2p7NkU-82yyM-TDiSPHs_NkSJA,26705
167
+ adam/sql/sql_completer.py,sha256=R19CGMIfDcpqixJ7-f4SVmKtNTY4FYgAVNNoACbkMsA,2402
168
+ adam/sql/state_machine.py,sha256=F_20_UorMd3v8g4SahEAN10CCQeirN5prxVGg77AG1Q,23884
168
169
  adam/sql/term_completer.py,sha256=bNnHAVf9NZl52xS_BQpikbOK39gDBJADnT9gSvG0iqI,2539
169
170
  adam/sso/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
170
171
  adam/sso/authenticator.py,sha256=BCm16L9zf5aLU47-sTCnudn2zLPwd8M2wwRminJfsqw,615
@@ -176,8 +177,8 @@ adam/sso/idp.py,sha256=fvcwUw_URTgsO6ySaqTIw0zQT2qRO1IPSGhf6rPtybo,5804
176
177
  adam/sso/idp_login.py,sha256=QAtCUeDTVWliJy40RK_oac8Vgybr13xH8wzeBoxPaa8,1754
177
178
  adam/sso/idp_session.py,sha256=9BUHNRf70u4rVKrVY1HKPOEmOviXvkjam8WJxmXSKIM,1735
178
179
  adam/sso/sso_config.py,sha256=5N8WZgIJQBtHUy585XLRWKjpU87_v6QluyNK9E27D5s,2459
179
- kaqing-2.0.70.dist-info/METADATA,sha256=CXfFNyxJYztdM8ZE6MW7MSPJ6LmxM63_fNGPBAH4THU,132
180
- kaqing-2.0.70.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
181
- kaqing-2.0.70.dist-info/entry_points.txt,sha256=SkzhuQJUWsXOzHeZ5TgQ2c3_g53UGK23zzJU_JTZOZI,39
182
- kaqing-2.0.70.dist-info/top_level.txt,sha256=8_2PZkwBb-xDcnc8a2rAbQeJhXKXskc7zTP7pSPa1fw,5
183
- kaqing-2.0.70.dist-info/RECORD,,
180
+ kaqing-2.0.71.dist-info/METADATA,sha256=gWzcAwMDBTOTuO7usJDlE_dDHQXG5WMWXjXS9CcM8A4,132
181
+ kaqing-2.0.71.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
182
+ kaqing-2.0.71.dist-info/entry_points.txt,sha256=SkzhuQJUWsXOzHeZ5TgQ2c3_g53UGK23zzJU_JTZOZI,39
183
+ kaqing-2.0.71.dist-info/top_level.txt,sha256=8_2PZkwBb-xDcnc8a2rAbQeJhXKXskc7zTP7pSPa1fw,5
184
+ kaqing-2.0.71.dist-info/RECORD,,