userver: /home/antonyzhilin/arcadia/taxi/uservices/userver/testsuite/pytest_plugins/pytest_userver/utils/tskv.py Source File
Loading...
Searching...
No Matches
tskv.py
1import re
2from typing import Dict
3from typing import Tuple
4
5TskvRow = Dict[str, str]
6
7
8_EQUALS_OR_BACKSLASH = re.compile('=|\\\\')
9_UNESCAPED_CHARS = {
10 'n': '\n',
11 'r': '\r',
12 't': '\t',
13 '0': '\0',
14 '\\': '\\',
15 '=': '=',
16}
17
18
19def _search_equals_or_backslash(s: str, start: int) -> int:
20 match = _EQUALS_OR_BACKSLASH.search(s, start)
21
22 return match.start() if match else -1
23
24
25def _search_backslash(s: str, start: int) -> int:
26 return s.find('\\', start)
27
28
29def _parse_pair(pair: str) -> Tuple[str, str]:
30 search_fn = _search_equals_or_backslash
31 key = None
32 unescaped_part = ''
33
34 start = 0
35 end = search_fn(pair, start)
36 while end != -1:
37 unescaped_part += pair[start:end]
38 if pair[end] == '=':
39 key = unescaped_part
40 unescaped_part = ''
41 search_fn = _search_backslash
42 elif end + 1 != len(pair) and pair[end + 1] in _UNESCAPED_CHARS:
43 unescaped_part += _UNESCAPED_CHARS[pair[end + 1]]
44 end += 1
45 else:
46 unescaped_part += '\\'
47
48 start = end + 1
49 end = search_fn(pair, start)
50
51 unescaped_part += pair[start:]
52
53 if key is None:
54 raise RuntimeError(f'Invalid tskv pair: {pair}')
55
56 return key, unescaped_part
57
58
59def parse_line(line: str) -> TskvRow:
60 parts = line.rstrip('\n').split('\t')
61 if parts[:1] != ['tskv']:
62 raise RuntimeError(f'Invalid tskv line: {line!r}')
63 return dict(map(_parse_pair, parts[1:]))