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

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

4 точки общо

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

  1import re
  2import itertools
  3
  4class BridgeKeeper:
  5    def __init__(self, module_name):
  6        self._module = __import__(module_name)
  7
  8    def __enter__(self):
  9        return self
 10
 11    def __exit__(self, exc_type, exc_val, exc_tb):
 12        pass
 13
 14    def __getattr__(self, name):
 15        obj = getattr(self._module, name)
 16
 17        obj_name = getattr(obj, '__name__')
 18        if not (obj_name and len(obj_name) != 0 and obj_name[0].isupper()):
 19            raise AttributeError(f"Invalid name")
 20
 21        if not callable(obj) or not self._test_quest_completion(obj):
 22            raise AttributeError(f"Cannot be called")
 23
 24        if not self._has_attribute(obj):
 25            raise AttributeError(f"No attribute works")
 26
 27        return obj
 28
 29    @staticmethod
 30    def _test_quest_completion(obj):
 31
 32        doc = obj.__doc__ or ""
 33        lines = doc.split("\n")
 34        start = len(lines)
 35        parameters = []
 36        for i in range(0,len(lines)):
 37            if lines[i] == 'Parameters':
 38                start = i+2
 39                break
 40        for j in range(start,len(lines)):
 41            if not lines[j].strip():
 42                break
 43
 44            parameters.append(BridgeKeeper._parse_line(lines[j]))
 45
 46        if start == len(lines):
 47            try:
 48                obj()
 49                return True
 50            except Exception:
 51                return False
 52
 53
 54        all_possibilities = itertools.product(*parameters)
 55
 56        try:
 57            for combination in all_possibilities:
 58                obj(*combination)
 59        except Exception:
 60            return False
 61        return True
 62
 63    @staticmethod
 64    def _parse_line(line):
 65        part = line
 66        if ':' in line:
 67            part = line.split(':')[1]
 68
 69        if '|' in part:
 70            res = []
 71            for option in part.split('|'):
 72                option = option.strip()
 73                res.extend(BridgeKeeper._parse_line(option))
 74            return res
 75
 76        dict_pattern = r'.*dict.*'
 77        set_pattern = r'.*set.*'
 78        list_pattern = r'.*list.*'
 79        tuple_pattern = r'.*tuple.*'
 80
 81        if re.match(dict_pattern, part):
 82            first_param = part.split('[')[1].split(']')[0].split(',')[0]
 83            second_param = part.split('[')[1].split(']')[0].split(',')[1]
 84            return [{BridgeKeeper.__parse_primitive(first_param) : BridgeKeeper._parse_primitive(second_param)}]
 85
 86        if re.match(set_pattern, part):
 87            first_param = part.split('[')[1].split(']')[0]
 88            return [{BridgeKeeper._parse_primitive(first_param)}]
 89
 90        if re.match(list_pattern, part):
 91            first_param = part.split('[')[1].split(']')[0]
 92            return [[BridgeKeeper._parse_primitive(first_param)]]
 93
 94        if re.match(tuple_pattern, part):
 95            first_param = part.split('[')[1].split(']')[0]
 96            return [(BridgeKeeper._parse_primitive(first_param), )]
 97
 98        return [BridgeKeeper._parse_primitive(part)]
 99
100    @staticmethod
101    def _parse_primitive(line):
102        if re.match(r'.*int.*', line):
103            return 1
104        if re.match(r'.*float.*', line):
105            return 1.0
106        if re.match(r'.*str.*', line):
107            return "This string is certainly very interesting"
108        if re.match(r'.*bool.*', line):
109            return True
110        if re.match(r'.*complex.*', line):
111            return 1+2j
112
113        return None
114
115    @staticmethod
116    def _has_attribute(obj):
117        for attr in dir(obj):
118            dunder_regex = r'__.*__'
119            if re.match(dunder_regex, attr):
120                continue
121            vowel_regex = r'.*[aeiouAEIOU]{4,}.*'
122            if re.match(vowel_regex, attr):
123                continue
124            last_latin_regex = r'[a-zA-Z]'
125            all_results = re.findall(last_latin_regex, attr)
126            if not all_results:
127                continue
128            if all_results[-1].isupper():
129                return True
130        return False

..E.........F............
======================================================================
ERROR: test_allows_dict_typed_parameter (test.TestBridgeKeeper.test_allows_dict_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 68, in test_allows_dict_typed_parameter
self.assertEqual(filtered.score_map({"alice": 3, "bob": 7}), 10)
^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 21, in __getattr__
if not callable(obj) or not self._test_quest_completion(obj):
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 44, in _test_quest_completion
parameters.append(BridgeKeeper._parse_line(lines[j]))
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/tmp/solution.py", line 84, in _parse_line
return [{BridgeKeeper.__parse_primitive(first_param) : BridgeKeeper._parse_primitive(second_param)}]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: type object 'BridgeKeeper' has no attribute '_BridgeKeeper__parse_primitive'

======================================================================
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

----------------------------------------------------------------------
Ran 25 tests in 0.003s

FAILED (failures=1, errors=1)

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