1import importlib
2import re
3
4
5class FilteredModule:
6 def __init__(self, module):
7 self._module = module
8
9 def __getattr__(self, name):
10 module = object.__getattribute__(self, '_module')
11
12 if not hasattr(module, name):
13 raise AttributeError(name)
14
15 obj = getattr(module, name)
16
17 if passes_all_three(obj):
18 return obj
19 raise AttributeError(name)
20
21def passes_all_three(obj):
22 return (check_first_question(obj) and
23 check_second_question(obj) and
24 check_third_question(obj))
25
26def check_first_question(obj):
27 if not hasattr(obj, '__name__'):
28 return False
29
30 return obj.__name__[0].isupper()
31
32def extract_params(obj):
33 doc = obj.__doc__ or ""
34
35 if "Parameters\n----------\n" not in doc:
36 return []
37
38 after = doc.split("Parameters\n----------\n")[1]
39
40 block = after.split("\n\n")[0] if "\n\n" in after else after
41
42 lines = block.strip().split("\n")
43
44 params = []
45 for line in lines:
46 name, type_str = line.split(" : ")
47 params.append((name.strip(), type_str.strip()))
48
49 return params
50
51BASE_TYPES = {
52 "int": 0,
53 "float": 0.0,
54 "str": "",
55 "bool": True,
56}
57
58def generate_value(type_str):
59 if "|" in type_str:
60 first = type_str.split("|")[0].strip()
61 return generate_value(first)
62
63 if "[" in type_str:
64 outer = type_str[:type_str.index("[")]
65 inner = type_str[type_str.index("[")+1:-1]
66
67 if outer == "dict":
68 key_type, val_type = inner.split(", ")
69 return {generate_value(key_type.strip()): generate_value(val_type.strip())}
70
71 inner_value = generate_value(inner)
72 if outer == "list":
73 return [inner_value]
74 if outer == "tuple":
75 return (inner_value,)
76 if outer == "set":
77 return {inner_value}
78
79 return BASE_TYPES[type_str]
80
81def check_second_question(obj):
82 if not callable(obj):
83 return False
84
85 params = extract_params(obj)
86 args = [generate_value(type_str) for name, type_str in params]
87
88 try:
89 obj(*args)
90 return True
91 except:
92 return False
93
94def check_third_question(obj):
95 for attr_name in dir(obj):
96 if attr_name.startswith('__') and attr_name.endswith('__'):
97 continue
98
99 letters = [c for c in attr_name if c.isalpha()]
100 if not letters or not letters[-1].isupper():
101 continue
102
103 if re.search(r'[aeiouAEIOU]{4,}', attr_name):
104 continue
105
106 return True
107 return False
108
109class BridgeKeeper:
110 def __init__(self, module_name):
111 self._module_name = module_name
112
113 def __enter__(self):
114 module = importlib.import_module(self._module_name)
115 return FilteredModule(module)
116
117 def __exit__(self, exc_type, exc_val, exc_tb):
118 pass
119
120
121# with BridgeKeeper("imported_module") as filtered_module:
122# filtered_module.baba(5, 'banichka')
123# filtered_module.lelq() # Връща "aa", защото отговаря на всички въпроси
124# filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3
125# filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а
............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)