Домашни > The Old Man from Scene #24 > Решения > Решението на Никола Нейчев

Резултати
3 точки от тестове
0 точки от учител

3 точки общо

19 успешни теста
6 неуспешни теста
Код
Скрий всички коментари

  1import importlib
  2
  3class BridgeKeeper:
  4    def __init__(self, module_name):
  5        self.module_name = module_name
  6
  7    def __enter__(self):
  8        module = importlib.import_module(self.module_name)
  9        return self.FilteredModule(module)
 10
 11    def __exit__(self, exc_type, exc_val, exc_tb):
 12        return False
 13
 14    class FilteredModule:
 15        def __init__(self, original_module):
 16            self._original = original_module
 17
 18        def __getattr__(self, name):
 19            obj = getattr(self._original, name)
 20            
 21            if self._passes_all_questions(obj):
 22                return obj
 23            raise AttributeError(f"BridgeKeeper rejects '{name}'")
 24
 25        def _passes_all_questions(self, obj):
 26            if not self._check_name(obj):
 27                return False
 28            if not self._check_quest(obj):
 29                return False
 30            if not self._check_random_question(obj):
 31                return False
 32            return True
 33
 34        def _check_name(self, obj):
 35            if not hasattr(obj, "__name__"):
 36                return False
 37            name = obj.__name__
 38            if not name:
 39                return False
 40            return name[0].isupper()
 41
 42        def _check_quest(self, obj):
 43            if not callable(obj):
 44                return False
 45            
 46            params = self._get_param_types(obj.__doc__)
 47            
 48            if not params:
 49                try:
 50                    obj()
 51                    return True
 52                except:
 53                    return False
 54            
 55            test_args = []
 56            for p in params:
 57                val = self._make_value(p)
 58                if val is None and p != "None":
 59                    return False
 60                test_args.append(val)
 61            
 62            try:
 63                obj(*test_args)
 64                return True
 65            except:
 66                return False
 67
 68        def _check_random_question(self, obj):
 69            vowels = set('aeiouAEIOU')
 70            
 71            for attr_name in dir(obj):
 72                if attr_name.startswith('__') and attr_name.endswith('__'):
 73                    continue
 74                
 75                seq_vowels = 0
 76                bad = False
 77                for ch in attr_name:
 78                    if ch in vowels:
 79                        seq_vowels += 1
 80                        if seq_vowels > 3:
 81                            bad = True
 82                            break
 83                    else:
 84                        seq_vowels = 0
 85                
 86                if bad:
 87                    continue
 88                
 89                last_alpha = None
 90                for ch in reversed(attr_name):
 91                    if ch.isalpha():
 92                        last_alpha = ch
 93                        break
 94                
 95                if last_alpha and last_alpha.isupper():
 96                    return True
 97            
 98            return False
 99
100        def _get_param_types(self, doc):
101            if not doc:
102                return []
103            
104            lines = doc.split('\n')
105            in_params = False
106            types = []
107            
108            for i in range(len(lines)):
109                line = lines[i].strip()
110                
111                if line == "Parameters" and i+1 < len(lines) and lines[i+1].strip() == "----------":
112                    in_params = True
113                    continue
114                
115                if in_params:
116                    if line == "":
117                        break
118                    
119                    if " : " in line:
120                        parts = line.split(" : ", 1)
121                        if len(parts) == 2:
122                            type_text = parts[1].strip()
123                            types.append(type_text)
124            
125            return types
126
127        def _make_value(self, type_string):
128            type_string = type_string.strip()
129            
130            if "|" in type_string:
131                type_string = type_string.split("|")[0].strip()
132            
133            if type_string == "int":
134                return 0
135            if type_string == "float":
136                return 0.0
137            if type_string == "str":
138                return ""
139            if type_string == "bool":
140                return True
141            if type_string == "None":
142                return None
143            
144            if type_string.startswith("list["):
145                return []
146            if type_string.startswith("tuple["):
147                return ()
148            if type_string.startswith("set["):
149                return set()
150            if type_string.startswith("dict["):
151                return {}
152            
153            return None

............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)

Дискусия
Виктор Бечев
30.04.2026 13:24

Ех, ако бяхме учили регулярни изрази, колко по-просто щеше да е на места. 😛
История
Това решение има само една версия.