1import re
2
3DUMMY_VALUES = {
4 'int': 0,
5 'float': 0.0,
6 'str': '',
7 'bool': False,
8 'list': [],
9 'tuple': (),
10 'set': set(),
11 'dict': {},
12}
13
14def _dummy_for_type(type_str):
15 base = type_str.strip().split('|')[0].strip().split('[')[0].strip()
16 return DUMMY_VALUES.get(base, 0)
17
18def _parse_docstring_params(obj):
19 doc = getattr(obj, '__doc__', None)
20 if not doc:
21 return []
22
23 match = re.search(r'Parameters\s*\n\s*-+\s*\n([\s\S]*?)(\n\s*\n|$)', doc)
24 if not match:
25 return []
26
27 args = []
28 for line in match.group(1).splitlines():
29 line = line.strip()
30 if re.match(r'\w+\s*:', line):
31 type_str = line.split(':', 1)[1].strip()
32 args.append(_dummy_for_type(type_str))
33 return args
34
35def _check_name(obj):
36 name = getattr(obj, '__name__', None)
37 return name is not None and name[0].isupper()
38
39def _check_quest(obj):
40 if not callable(obj):
41 return False
42 args = _parse_docstring_params(obj)
43 try:
44 obj(*args)
45 return True
46 except Exception:
47 return False
48
49def _check_attribute(obj):
50 for attr in dir(obj):
51 last = None
52 for sym in reversed(attr):
53 if sym != '_' and not sym.isdigit():
54 last = sym
55 break
56 if last is None or not last.isupper():
57 continue
58
59 max_run = run = 0
60 for sym in attr.lower():
61 if sym in 'aeiou':
62 run += 1
63 max_run = max(max_run, run)
64 else:
65 run = 0
66 if max_run > 3:
67 continue
68
69 return True
70 return False
71
72
73def _passes_all(obj):
74 return _check_name(obj) and _check_quest(obj) and _check_attribute(obj)
75
76class _FilteredModule:
77 def __init__(self, module):
78 self.__dict__['_module'] = module
79
80 def __getattr__(self, name):
81 obj = getattr(self.__dict__['_module'], name)
82 if not _passes_all(obj):
83 raise AttributeError(f"Wrong, '{name}'! You have failed to answer correctly - prepare to be cast into the Gorge of Eternal Peril!")
84 return obj
85
86class BridgeKeeper:
87 def __init__(self, module):
88 self._module = module
89
90 def __enter__(self):
91 return _FilteredModule(__import__(self._module))
92
93 def __exit__(self, exc_type, exc_val, exc_tb):
94 return False
............F.F..F...F.FF
======================================================================
FAIL: test_rejects_callable_when_parameter_names_do_not_match (test.TestBridgeKeeper.test_rejects_callable_when_parameter_names_do_not_match)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 59, in test_rejects_callable_when_parameter_names_do_not_match
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
======================================================================
FAIL: test_rejects_dict_when_callable_does_not_work_with_documented_key_and_value_types (test.TestBridgeKeeper.test_rejects_dict_when_callable_does_not_work_with_documented_key_and_value_types)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 90, in test_rejects_dict_when_callable_does_not_work_with_documented_key_and_value_types
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
======================================================================
FAIL: test_rejects_list_when_callable_does_not_work_with_documented_element_type (test.TestBridgeKeeper.test_rejects_list_when_callable_does_not_work_with_documented_element_type)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 102, in test_rejects_list_when_callable_does_not_work_with_documented_element_type
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
======================================================================
FAIL: test_rejects_set_when_callable_does_not_work_with_documented_element_type (test.TestBridgeKeeper.test_rejects_set_when_callable_does_not_work_with_documented_element_type)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 112, in test_rejects_set_when_callable_does_not_work_with_documented_element_type
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
======================================================================
FAIL: test_rejects_tuple_when_callable_does_not_work_with_documented_element_type (test.TestBridgeKeeper.test_rejects_tuple_when_callable_does_not_work_with_documented_element_type)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 107, in test_rejects_tuple_when_callable_does_not_work_with_documented_element_type
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
======================================================================
FAIL: test_rejects_union_when_callable_does_not_support_all_union_branches (test.TestBridgeKeeper.test_rejects_union_when_callable_does_not_support_all_union_branches)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 72, in test_rejects_union_when_callable_does_not_support_all_union_branches
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
----------------------------------------------------------------------
Ran 25 tests in 0.003s
FAILED (failures=6)
01.05.2026 15:31