1import inspect
2import re
3
4
5class FilteredModule:
6 def __init__(self, module):
7 self._module = module
8
9 def __getattr__(self, name):
10 obj = getattr(self._module, name)
11
12 if BridgeKeeper.ask_questions(obj):
13 return obj
14
15 raise AttributeError(name)
16
17
18class BridgeKeeper:
19 def __init__(self, module_name):
20 self.module_name = module_name
21 self.module = None
22
23 def __enter__(self):
24 self.module = __import__(self.module_name)
25 return FilteredModule(self.module)
26
27 def __exit__(self, exc_type, exc_value, traceback):
28 pass
29
30 @classmethod
31 def ask_questions(cls, obj):
32 return cls._what_is_your_name(obj) and cls._what_is_your_quest(obj) and cls._what_is(obj)
33
34 @classmethod
35 def _what_is_your_name(cls, obj):
36 name = getattr(obj, "__name__", None)
37 if not isinstance(name, str) or not name:
38 return False
39 return name[0].isupper()
40
41 @classmethod
42 def _what_is_your_quest(cls, obj):
43 if not callable(obj):
44 return False
45
46 docstring = inspect.getdoc(obj) or ""
47 match = re.search(
48 r"^Parameters[ \t]*\n-{10}[ \t]*\n(.*?)(?=\n[ \t]*\n|\Z)",
49 docstring,
50 re.DOTALL | re.MULTILINE,
51 )
52 parameters = match.group(1).strip().splitlines() if match else []
53 parsed_parameters = []
54
55 for parameter in parameters:
56 parameter = parameter.strip()
57 if not parameter:
58 continue
59
60 name, _ = parameter.split(":", 1)
61 parsed_parameters.append(name.strip())
62
63 try:
64 signature = inspect.signature(obj)
65 except (TypeError, ValueError):
66 return False
67
68 return list(signature.parameters.keys()) == parsed_parameters
69
70 @classmethod
71 def _what_is(cls, obj):
72 for name in dir(obj):
73 if name.startswith("__") and name.endswith("__"):
74 continue
75
76 if re.search(r"[aeiou]{4,}", name.lower()):
77 continue
78
79 for char in reversed(name):
80 if "a" <= char.lower() <= "z":
81 if char.isupper():
82 return True
83 break
84
85 return False
..............F..F...F.FF
======================================================================
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=5)