Домашни > The Old Man from Scene #24 > Решения > Решението на Захари Янев

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

4 точки общо

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

  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)

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