Домашни > The Old Man from Scene #24 > Решения > Решението на Емилияна Атанасова

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

4 точки общо

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

  1import importlib
  2import re
  3
  4
  5class BridgeKeeper:
  6    def __init__(self, module_name):
  7        self.module_name = module_name
  8
  9    def __enter__(self):
 10        module = importlib.import_module(self.module_name)
 11        return _FilteredModule(module)
 12
 13    def __exit__(self, exc_type, exc_val, exc_tb):
 14        return False
 15
 16
 17class _FilteredModule:
 18    def __init__(self, module):
 19        self._module = module
 20
 21    def __getattr__(self, name):
 22        obj = getattr(self._module, name)
 23        if (
 24            _valid_name(obj)
 25            and _valid_callable(obj)
 26            and _has_valid_attribute(obj)
 27        ):
 28            return obj
 29        raise AttributeError(f"{name} is not worthy!")
 30
 31
 32def _valid_name(obj):
 33    name = getattr(obj, "__name__", None)
 34    return isinstance(name, str) and name and name[0].isupper()
 35
 36def _valid_callable(obj):
 37    if not callable(obj):
 38        return False
 39    params = _parse_docstring(obj)
 40    try:
 41        args = [_dummy_value(t) for t in params]
 42        obj(*args)
 43        return True
 44    except Exception:
 45        return False
 46
 47def _parse_docstring(obj):
 48    doc = obj.__doc__
 49    if not doc:
 50        return []
 51    match = re.search(
 52        r"Parameters\s*-+\s*(.*?)(\n\s*\n|$)",
 53        doc,
 54        re.DOTALL,
 55    )
 56    if not match:
 57        return []
 58    block = match.group(1).strip().splitlines()
 59    result = []
 60    for line in block:
 61        line = line.strip()
 62        if not line or ":" not in line:
 63            continue
 64        _, type_part = line.split(":", 1)
 65        result.append(type_part.strip())
 66    return result
 67
 68def _dummy_value(type_str):
 69    if "|" in type_str:
 70        type_str = type_str.split("|")[0].strip()
 71    collection_match = re.match(r"(list|tuple|set)\[(.+)\]", type_str)
 72    if collection_match:
 73        collection, inner = collection_match.groups()
 74        val = _dummy_value(inner)
 75        if collection == "list":
 76            return [val]
 77        elif collection == "tuple":
 78            return (val,)
 79        elif collection == "set":
 80            return {val}
 81    dict_match = re.match(r"dict\[(.+),(.+)\]", type_str)
 82    if dict_match:
 83        k, v = dict_match.groups()
 84        return {_dummy_value(k.strip()): _dummy_value(v.strip())}
 85    mapping = {
 86        "int": 1,
 87        "float": 1.0,
 88        "str": "a",
 89        "bool": True,
 90    }
 91    return mapping.get(type_str, None)
 92
 93def _has_valid_attribute(obj):
 94    for attr in dir(obj):
 95        if attr.startswith("__") and attr.endswith("__"):
 96            continue
 97        if _valid_attribute_name(attr):
 98            return True
 99    return False
100
101def _valid_attribute_name(name):
102    if re.search(r"[aeiouAEIOU]{4,}", name):
103        return False
104    letters = [c for c in name if c.isalpha()]
105    if not letters:
106        return False
107    if not letters[-1].isupper():
108        return False
109    return True

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

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