Домашни > The Old Man from Scene #24 > Решения > Решението на Александър Ангелов

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

4 точки общо

23 успешни теста
2 неуспешни теста
Код

  1import importlib
  2import re
  3
  4
  5class FilteredModule:
  6
  7    def __init__(self, module):
  8        self.module = module
  9
 10    def __getattr__(self, name):
 11        obj = getattr(self.module, name)
 12
 13        if (
 14            self.passes_name_question(obj) 
 15            and self.passes_func_callable(obj) 
 16            and self.passes_correct_arguments(obj) 
 17            and self.passes_random_question(obj)
 18        ):
 19            return obj
 20        
 21        raise AttributeError
 22
 23    def passes_name_question(self, obj):
 24        return hasattr(obj, "__name__") and obj.__name__[0].isupper()
 25
 26    def passes_func_callable(self, obj):
 27        return callable(obj)
 28
 29    def passes_correct_arguments(self, obj):
 30        doc = getattr(obj, "__doc__", None) or ""
 31
 32        block = self.get_parameters_block(doc)
 33        
 34        if block == "":
 35            try:
 36                obj()
 37                return True
 38            except Exception:
 39                return False
 40            
 41        parameters = self.parse_parameters(block)
 42        args = [self.example_value_for_type(type_text) for _, type_text in parameters]
 43        
 44        try:
 45            obj(*args)
 46            return True
 47        except Exception:
 48            return False
 49
 50    def get_parameters_block(self, doc):
 51        pattern = r"Parameters\n----------\n(.*?)(?:\n\n|$)"
 52
 53        match = re.search(pattern, doc, re.S)
 54
 55        if match is None:
 56            return ""
 57
 58        return match.group(1).strip()
 59    
 60    def parse_parameters(self, block):
 61        parameters = []
 62
 63        for line in block.splitlines():
 64            line = line.strip()
 65
 66            if " : " not in line:
 67                continue
 68
 69            name, type_text = line.split(" : ", 1)
 70
 71            parameters.append((name, type_text))
 72
 73        return parameters
 74    
 75    def example_value_for_type(self, type_text):
 76        type_text = type_text.strip()
 77
 78        if " | " in type_text:
 79            first_type = type_text.split(" | ", 1)[0]
 80            return self.example_value_for_type(first_type)
 81        
 82        if type_text.startswith("dict[") and type_text.endswith("]"):
 83            inner = type_text[5:-1]
 84            key_type, value_type = inner.split(",", 1)
 85
 86            key = self.example_value_for_type(key_type.strip())
 87            value = self.example_value_for_type(value_type.strip())
 88
 89            return {key: value}
 90        
 91        if type_text.startswith("list[") and type_text.endswith("]"):
 92            inner_type = type_text[5:-1]
 93            return [self.example_value_for_type(inner_type)]
 94
 95        if type_text.startswith("tuple[") and type_text.endswith("]"):
 96            inner_type = type_text[6:-1]
 97            return (self.example_value_for_type(inner_type),)
 98
 99        if type_text.startswith("set[") and type_text.endswith("]"):
100            inner_type = type_text[4:-1]
101            return {self.example_value_for_type(inner_type)}
102
103        examples = {
104            "int": 1,
105            "str": "a",
106            "float": 1.0,
107            "bool": True,
108        }
109
110        return examples[type_text]
111    
112    def passes_random_question(self, obj):
113        for attr_name in dir(obj):
114            if self.is_dunder(attr_name):
115                continue
116
117            if self.has_too_many_consecutive_vowels(attr_name):
118                continue
119
120            if not self.last_latin_letter_is_upper(attr_name):
121                continue
122
123            return True
124        
125        return False
126
127    def is_dunder(self, attr_name):
128        return attr_name.startswith("__") and attr_name.endswith("__")
129    
130    def has_too_many_consecutive_vowels(self, attr_name):
131        vowels = "aeiou"
132        count = 0
133
134        for char in attr_name.lower():
135            if char in vowels:
136                count += 1
137
138                if count > 3:
139                    return True
140            else:
141                count = 0
142
143        return False
144    
145    def last_latin_letter_is_upper(self, attr_name):
146        for char in reversed(attr_name):
147            if char.isalpha() and char.isascii():
148                return char.isupper()
149
150        return False
151
152
153class BridgeKeeper:
154
155    def __init__(self, module_name):
156        self.module_name = module_name
157
158    def __enter__(self):
159        module = importlib.import_module(self.module_name)
160        return FilteredModule(module)
161    
162    def __exit__(self, exc_type, exc_value, traceback):
163        pass

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

Дискусия
История
Това решение има само една версия.