1import importlib
2import re
3
4class BridgeKeeper:
5 def __init__(self, module_name):
6 self.module_name = module_name
7 self.module = None
8
9 def __enter__(self):
10 self.module = importlib.import_module(self.module_name)
11 return self
12
13 def __exit__(self, exc_type, exc_val, exc_tb):
14 return False
15
16 def __getattr__(self, name):
17 if not hasattr(self.module, name):
18 raise AttributeError(f"Module '{self.module_name}' has no attribute '{name}'")
19 obj = getattr(self.module, name)
20 if not self._check_name(obj):
21 raise AttributeError(f"Object '{name}' does not pass the name check")
22 if not self._check_quest(obj):
23 raise AttributeError(f"Object '{name}' does not pass the quest check")
24 if not self._check_random_question(obj):
25 raise AttributeError(f"Object '{name}' does not pass the random question check")
26 return obj
27
28 def _check_name(self, obj):
29 if not hasattr(obj, '__name__'):
30 return False
31 return len(obj.__name__) > 0 and obj.__name__[0].isupper()
32
33 def _check_quest(self, obj):
34 if not callable(obj):
35 return False
36 doc = getattr(obj, '__doc__', '') or ''
37 match = re.search(r'Parameters\n----------\n(.*?)(\n\n|$)', doc, re.DOTALL)
38 if match:
39 lines = match.group(1).splitlines()
40 types = [line.split(":", 1)[1].strip() for line in lines if ":" in line and not line.strip().startswith(":")]
41 else:
42 types = []
43 try:
44 args = [self._create_value(t) for t in types]
45 obj(*args)
46 return True
47 except Exception:
48 return False
49
50 def _create_value(self, t):
51 t = t.strip()
52 if "|" in t:
53 return self._create_value(t.split("|")[0])
54 if t.startswith("list["):
55 inner = t[5:-1]
56 return [self._create_value(inner)]
57 if t.startswith("tuple["):
58 inner = t[6:-1]
59 return (self._create_value(inner),)
60 if t.startswith("set["):
61 inner = t[4:-1]
62 return {self._create_value(inner)}
63 if t.startswith("dict["):
64 inner = t[5:-1]
65 k, v = inner.split(",")
66 return {self._create_value(k.strip()): self._create_value(v.strip())}
67 return {"int": 1, "float": 1.0, "str": "a", "bool": True}.get(t, None)
68
69 def _check_random_question(self, obj):
70 for attr_name in dir(obj):
71 if attr_name.startswith('__') and attr_name.endswith('__'):
72 continue
73 if self._has_more_than_3_consecutive_vowels(attr_name):
74 continue
75 if not self._last_letter_is_uppercase(attr_name):
76 continue
77 return True
78 return False
79
80 def _has_more_than_3_consecutive_vowels(self, s):
81 return bool(re.search(r'[aeiouAEIOU]{4,}', s))
82
83 def _last_letter_is_uppercase(self, s):
84 letters = [symbol for symbol in s if symbol.isalpha()]
85 return letters and letters[-1].isupper()
............F...........F
======================================================================
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_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.002s
FAILED (failures=2)