1import importlib
2import re
3import inspect
4
5#will only work if the modules are withing the same directory
6
7class BridgeKeeper:
8
9 def __init__(self, module_name):
10 self.module_name = module_name
11
12 def __enter__(self):
13 module = importlib.import_module(self.module_name)
14 valid_objects = {}
15
16 for name, obj in module.__dict__.items():
17 if not (hasattr(obj, "__name__") and obj.__name__[0].isupper()):
18 continue
19
20 if not callable(obj) or not self.match_docstring(obj.__doc__, obj.__call__):
21 continue
22
23 if not self.has_right_attribute(obj):
24 continue
25
26 valid_objects[name] = obj
27
28 return DotList(valid_objects)
29
30 def __exit__(self, exc_type, exc, tb):
31 pass
32
33 def match_docstring(self, docstring, call_method):
34 res = []
35
36 if docstring is not None:
37 res = re.search(r"(?<=Parameters\n----------\n)([\s\S]*?)(?=\n\n|$)", docstring)
38
39 if res:
40 raw_params = res.group()
41
42 sig = inspect.signature(call_method)
43
44 actual_params = list(sig.parameters.keys())
45
46 if 'self' in actual_params:
47
48 actual_params.remove('self')
49
50 if not res:
51
52 if not actual_params:
53
54 return True
55
56 return False
57 count = 0
58 for line in raw_params.splitlines():
59 count += 1
60
61 if count == len(actual_params):
62 return True
63
64 return False
65
66 def has_right_attribute(self, object):
67
68 for attr_name in dir(object):
69
70 if attr_name.startswith("__") and attr_name.endswith("__"):
71 continue
72
73 if re.search(r"[aouei]{4,}", attr_name, re.IGNORECASE):
74 continue
75
76 for char in reversed(attr_name):
77 if char.isalpha():
78 if char.isupper():
79 return True
80 return False
81
82 return False
83
84class DotList:
85
86 def __init__(self, data):
87 self.data = data
88
89 def __getattr__(self, name):
90
91 if name in self.data:
92 return self.data[name]
93 else:
94 raise AttributeError(f"The object does not meet the requirements! ({name})")
E.E.EEEE.EE.F..FF........
======================================================================
ERROR: test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues (test.TestBridgeKeeper.test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 55, in test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues
self.assertEqual(filtered.trailing_marker(7), 70)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (trailing_marker)
======================================================================
ERROR: test_allows_dict_typed_parameter (test.TestBridgeKeeper.test_allows_dict_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 68, in test_allows_dict_typed_parameter
self.assertEqual(filtered.score_map({"alice": 3, "bob": 7}), 10)
^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (score_map)
======================================================================
ERROR: test_allows_set_typed_parameter (test.TestBridgeKeeper.test_allows_set_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 77, in test_allows_set_typed_parameter
self.assertEqual(filtered.gather_tags({"bridge", "keeper"}), "bridge,keeper")
^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (gather_tags)
======================================================================
ERROR: test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder (test.TestBridgeKeeper.test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 64, in test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder
self.assertEqual(filtered.trailing_underscores(4), 5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (trailing_underscores)
======================================================================
ERROR: test_allows_third_answer_with_single_uppercase_letter_name (test.TestBridgeKeeper.test_allows_third_answer_with_single_uppercase_letter_name)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 117, in test_allows_third_answer_with_single_uppercase_letter_name
self.assertEqual(filtered.single_letter_answer(5), 15)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (single_letter_answer)
======================================================================
ERROR: test_allows_union_typed_parameter (test.TestBridgeKeeper.test_allows_union_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 17, in test_allows_union_typed_parameter
self.assertEqual(filtered.sum_group([1, 2, 3]), 6)
^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (sum_group)
======================================================================
ERROR: test_allows_zero_arg_callable_when_parameters_block_is_missing (test.TestBridgeKeeper.test_allows_zero_arg_callable_when_parameters_block_is_missing)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 13, in test_allows_zero_arg_callable_when_parameters_block_is_missing
self.assertEqual(filtered.silent_oracle(), 42)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (silent_oracle)
======================================================================
ERROR: test_allows_zero_arg_callable_with_missing_docstring (test.TestBridgeKeeper.test_allows_zero_arg_callable_with_missing_docstring)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 51, in test_allows_zero_arg_callable_with_missing_docstring
self.assertEqual(filtered.ghost_zero(), "boo")
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __getattr__
raise AttributeError(f"The object does not meet the requirements! ({name})")
AttributeError: The object does not meet the requirements! (ghost_zero)
======================================================================
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_docstring_with_arity_mismatch (test.TestBridgeKeeper.test_rejects_docstring_with_arity_mismatch)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 46, in test_rejects_docstring_with_arity_mismatch
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
======================================================================
FAIL: test_rejects_docstring_with_parameter_order_mismatch (test.TestBridgeKeeper.test_rejects_docstring_with_parameter_order_mismatch)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 41, in test_rejects_docstring_with_parameter_order_mismatch
with self.assertRaises(AttributeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
AssertionError: AttributeError not raised
----------------------------------------------------------------------
Ran 25 tests in 0.053s
FAILED (failures=3, errors=8)
30.04.2026 13:44
30.04.2026 13:50
30.04.2026 13:46
30.04.2026 13:52
30.04.2026 13:48