Домашни > The Old Man from Scene #24 > Решения > Решението на Кристиян Тодоров

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

4 точки общо

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

  1import importlib
  2import inspect
  3import re
  4import itertools
  5
  6
  7def _valid_name(obj):
  8    name = getattr(obj, "__name__", None)
  9    return isinstance(name, str) and name and name[0].isupper()
 10
 11
 12def _valid_attr(obj):
 13    for attr in dir(obj):
 14        if attr.startswith("__") and attr.endswith("__"):
 15            continue
 16        if re.search(r"[aeiouAEIOU]{4,}", attr):
 17            continue
 18        letters = [ch for ch in attr if ch.isalpha()]
 19        if not letters:
 20            continue
 21        if letters[-1].isupper():
 22            return True
 23    return False
 24
 25
 26def _parse_doc_params(obj):
 27    doc = inspect.getdoc(obj)
 28    if not doc:
 29        return []
 30
 31    match = re.search(r"Parameters\n----------\n(.*?)(\n\s*\n|\Z)", doc, re.DOTALL)
 32    if not match:
 33        return []
 34
 35    params = []
 36    for line in match.group(1).splitlines():
 37        line = line.strip()
 38        m = re.match(r"^([A-Za-z_]\w*)\s*:\s*(.+)$", line)
 39        if m:
 40            params.append((m.group(1), m.group(2).strip()))
 41    return params
 42
 43
 44def _sample_for_type(t):
 45    t = t.strip()
 46
 47    if "|" in t:
 48        parts = t.split("|")
 49        res = []
 50        for p in parts:
 51            res += _sample_for_type(p.strip())
 52        return res
 53
 54    if t.startswith("list["):
 55        inner = t[5:-1]
 56        return [[_sample_for_type(inner)[0]]]
 57
 58    if t.startswith("tuple["):
 59        inner = t[6:-1]
 60        return [(_sample_for_type(inner)[0],)]
 61
 62    if t.startswith("set["):
 63        inner = t[4:-1]
 64        try:
 65            return [{_sample_for_type(inner)[0]}]
 66        except:
 67            return []
 68
 69    if t.startswith("dict["):
 70        inner = t[5:-1]
 71        k, v = inner.split(",")
 72        return [{_sample_for_type(k.strip())[0]: _sample_for_type(v.strip())[0]}]
 73
 74    basics = {
 75        "int": 7,
 76        "float": 7.5,
 77        "str": "Z",
 78        "bool": True,
 79        "bytes": b"Z",
 80        "complex": 7 + 0j,
 81        "None": None,
 82        "NoneType": None,
 83    }
 84
 85    if t in basics:
 86        return [basics[t]]
 87
 88    return []
 89
 90
 91def _callable_works(obj):
 92    params = _parse_doc_params(obj)
 93
 94    if not params:
 95        try:
 96            obj()
 97            return True
 98        except Exception:
 99            return False
100
101    try:
102        sig = inspect.signature(obj)
103    except Exception:
104        return False
105
106    sig_params = list(sig.parameters.values())
107    if len(sig_params) != len(params):
108        return False
109
110    for sp, (doc_name, _) in zip(sig_params, params):
111        if sp.name != doc_name:
112            return False
113
114    all_samples = []
115    for _, type_str in params:
116        samples = _sample_for_type(type_str)
117        if not samples:
118            return False
119        all_samples.append(samples)
120
121    for combo in itertools.product(*all_samples):
122        try:
123            obj(*combo)
124        except Exception:
125            return False
126
127    return True
128
129
130def _qualifies(obj):
131    return (
132        _valid_name(obj) and callable(obj) and _valid_attr(obj) and _callable_works(obj)
133    )
134
135
136class _FilteredModule:
137    def __init__(self, module):
138        self._module = module
139
140    def __getattr__(self, name):
141        try:
142            obj = getattr(self._module, name)
143        except AttributeError:
144            raise AttributeError(name)
145
146        if _qualifies(obj):
147            return obj
148        raise AttributeError(name)
149
150
151class BridgeKeeper:
152    def __init__(self, module_name):
153        self._module_name = module_name
154
155    def __enter__(self):
156        module = importlib.import_module(self._module_name)
157        return _FilteredModule(module)
158
159    def __exit__(self, exc_type, exc, tb):
160        return False

.........................
----------------------------------------------------------------------
Ran 25 tests in 0.002s

OK

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

На пръв поглед решението изглежда по-сложно, отколкото е, но всъщност се чете лесно. Дали може по-добре - със сигурност, например `_sample_for_type` няма да пострада от рефакториране, но предвид дизайн решенията, които си взел - доста прилично.
История
Това решение има само една версия.