Домашни > The Old Man from Scene #24 > Решения > Решението на Иван Грозданов

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

4 точки общо

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

  1import importlib
  2import inspect
  3import itertools
  4import re
  5
  6class BridgeKeeper:
  7    def __init__(self, module: str):
  8        self.__module = importlib.import_module(module)
  9
 10    def __enter__(self):
 11        self.__allowed_atributes = []
 12        for attr in dir(self.__module):
 13            if self.is_allowed(attr):
 14                self.__allowed_atributes.append(attr)
 15        return self
 16
 17    def is_allowed(self, attribute: str) -> bool:
 18        obj = getattr(self.__module, attribute)
 19        return self.what_is_your_name(obj) and self.what_is_your_request(obj) and self.what_is(obj)
 20        
 21
 22    def what_is_your_name(self, obj) -> bool:
 23        try:
 24            return bool(re.search(r"^[A-Z]", obj.__name__))
 25        except Exception:
 26            return False
 27
 28    def what_is_your_request(self, obj) -> bool:
 29        if not callable(obj):
 30            return False
 31
 32        doc = inspect.getdoc(obj) or ""
 33
 34        block = re.search(
 35            r"(?ms)^Parameters\s*\n[\-]+\s*\n(.*?)(?:\n\s*\n|\Z)",
 36            doc,
 37        )
 38
 39        params = [] if not block else re.findall(r"^\s*(\w+)\s*:\s*(.+?)\s*$", block.group(1), re.MULTILINE)
 40
 41        try:
 42            real_names = list(inspect.signature(obj).parameters)
 43            doc_names = [name for name, _ in params]
 44
 45            if real_names != doc_names:
 46                return False
 47
 48            args_options = []
 49
 50            for _, type_name in params:
 51                value = self.value_from_type(type_name)
 52
 53                if "|" in type_name:
 54                    args_options.append(value)
 55                else:
 56                    args_options.append([value])
 57
 58            for args in itertools.product(*args_options):
 59                obj(*args)
 60
 61            return True
 62
 63        except Exception:
 64            return False
 65
 66    def value_from_type(self, type_name: str):
 67        type_name = type_name.strip()
 68
 69        base_values = {
 70            "int": 1,
 71            "float": 1.0,
 72            "str": "x",
 73            "bool": True,
 74            "bytes": b"x",
 75            "complex": 1 + 0j,
 76        }
 77
 78        collections = {
 79            "list": lambda x: [x],
 80            "set": lambda x: {x},
 81            "tuple": lambda x: (x,),
 82        }
 83
 84        union_parts = re.split(rf"\s*{re.escape("|")}\s*(?![^\[]*\])", type_name)
 85
 86        if len(union_parts) > 1:
 87            return self.value_from_type(union_parts[0])
 88
 89        if type_name in base_values:
 90            return base_values[type_name]
 91
 92        match = re.match(r"^(list|set|tuple)\[(.+)\]$", type_name)
 93        if match:
 94            collection_name, inner_type = match.groups()
 95            return collections[collection_name](self.value_from_type(inner_type))
 96
 97        match = re.match(r"^dict\[(.+)\]$", type_name)
 98        if match:
 99            key_type, value_type = re.split(rf"\s*{re.escape(",")}\s*(?![^\[]*\])", match.group(1))
100            return {self.value_from_type(key_type): self.value_from_type(value_type)}
101
102        return object()
103
104    def what_is(self, obj) -> bool:
105        for attr in dir(obj):
106            if self.is_valid_answer(attr):
107                return True
108        return False
109
110    def is_valid_answer(self, attr: str) -> bool:
111        if attr.startswith("__") and attr.endswith("__") or re.search(r"[aeiouAEIOU]{4,}", attr):
112            return False
113        latin_letters = re.findall(r"[a-zA-Z]", attr)
114        return bool(latin_letters) and latin_letters[-1].isupper()
115
116    def __getattr__(self, name):
117        if name in self.__allowed_atributes:
118            return getattr(self.__module, name)
119        raise AttributeError(name)
120
121    def __exit__(self, exc_type, exc_val, exc_tb):
122        return False

...E...E.................
======================================================================
ERROR: test_allows_multi_argument_union_bonus_case (test.TestBridgeKeeper.test_allows_multi_argument_union_bonus_case)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 95, in test_allows_multi_argument_union_bonus_case
self.assertEqual(filtered.triple_union_pair(3, [1, 2]), 6)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 119, in __getattr__
raise AttributeError(name)
AttributeError: triple_union_pair

======================================================================
ERROR: test_allows_union_typed_parameter (test.TestBridgeKeeper.test_allows_union_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 17, in test_allows_union_typed_parameter
self.assertEqual(filtered.sum_group([1, 2, 3]), 6)
^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 119, in __getattr__
raise AttributeError(name)
AttributeError: sum_group

----------------------------------------------------------------------
Ran 25 tests in 0.028s

FAILED (errors=2)

Дискусия
Виктор Бечев
01.05.2026 15:17

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