Coverage for utils/check.py : 48%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
3# -- stdlib --
4import types
5from typing import List
7# -- third party --
8# -- own --
11# -- code --
12class CheckFailed(Exception):
13 path: List[str]
15 def __init__(self):
16 Exception.__init__(self)
17 self.path = []
19 def path_string(self):
20 return ''.join([
21 self._path_fragment(v)
22 for v in self.path
23 ])
25 def _path_fragment(self, v):
26 if isinstance(v, int):
27 return '[%s]' % v
28 elif isinstance(v, str):
29 return '.%s' % v
31 def finalize(self):
32 self.args = (self.path_string(), )
35def check(cond):
36 if not cond:
37 raise CheckFailed
40def _check_isinstance(obj, cls):
41 try:
42 check(isinstance(obj, cls))
43 except TypeError as e:
44 raise CheckFailed from e
47_check_key_not_exists = object()
50def check_type_exc(pattern, obj, path=None):
51 try:
52 if isinstance(pattern, (list, tuple)):
53 _check_isinstance(obj, (list, tuple))
54 if len(pattern) == 2 and pattern[-1] is ...:
55 cls = pattern[0]
56 for i, v in enumerate(obj):
57 check_type_exc(cls, v, i)
58 else:
59 check(len(pattern) == len(obj))
60 for i, (cls, v) in enumerate(zip(pattern, obj)):
61 check_type_exc(cls, v, i)
63 elif isinstance(pattern, dict): 63 ↛ 64line 63 didn't jump to line 64, because the condition on line 63 was never true
64 _check_isinstance(obj, dict)
65 if ... in pattern:
66 pattern = dict(pattern)
67 match = pattern.pop(...)
68 else:
69 match = '!'
71 if match in set('?!='):
72 lkeys = set(pattern.keys())
73 rkeys = set(obj.keys())
75 if match == '!':
76 iterkeys = lkeys
77 elif match == '?':
78 iterkeys = lkeys & rkeys
79 elif match == '=':
80 check(lkeys == rkeys)
81 iterkeys = lkeys
82 else:
83 assert False, 'WTF?!'
85 for k in iterkeys:
86 check_type_exc(pattern[k], obj.get(k, _check_key_not_exists), k)
88 elif match is ...:
89 assert len(pattern) == 1, 'Invalid dict pattern'
90 kt, vt = list(pattern.items())[0]
91 for k in obj:
92 check_type_exc(kt, k, '<%s>' % kt.__name__)
93 check_type_exc(vt, obj[k], k)
94 else:
95 assert False, 'Invalid dict match type'
97 else:
98 if issubclass(type(pattern), types.FunctionType): 98 ↛ 99line 98 didn't jump to line 99, because the condition on line 98 was never true
99 try:
100 check(pattern(obj))
101 except Exception as e:
102 raise CheckFailed from e
103 elif issubclass(type(pattern), (int, str, bytes, tuple)): 103 ↛ 104line 103 didn't jump to line 104, because the condition on line 103 was never true
104 check(obj == pattern)
105 else:
106 _check_isinstance(obj, pattern)
108 except CheckFailed as e:
109 if path is not None: 109 ↛ 110line 109 didn't jump to line 110, because the condition on line 109 was never true
110 e.path.insert(0, path)
111 else:
112 e.finalize()
114 raise
117'''
118def check_type(pattern, obj):
119 try:
120 check_type_exc(pattern, obj)
121 return None
122 except CheckFailed as e:
123 return e.path_string()
124'''
126check_type = check_type_exc