Домашни > The Old Man from Scene #24 > Решения > Решението на Магдалена Дичева

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

2 точки общо

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

  1import inspect
  2
  3class BridgeKeeper:
  4    def __init__(self, module):
  5        self.module = module
  6     
  7    def __enter__(self):
  8        return self.View(self.module)
  9    
 10    def __exit__(self, error_type, error_value, error_trace):
 11        return False
 12    
 13
 14    class View:
 15        def __init__(self, module):
 16            self.module = module
 17        
 18        def __getattr__(self, name):
 19            if name not in self.module:
 20                raise AttributeError(name)
 21            obj = self.module[name]
 22            if not self._check_name(obj):
 23                raise AttributeError(name)
 24            if not self._check_callable(obj):
 25                raise AttributeError(name)
 26            if not self._check_hidden(obj):
 27                raise AttributeError(name)
 28            return obj
 29        
 30        def _check_name(self, obj):
 31            if not hasattr(obj, "__name__"):
 32                return False
 33            name = obj.__name__
 34            return isinstance(name, str) and name and name[0].isupper()
 35        
 36        def _check_callable(self, obj):
 37            if not callable(obj):
 38                return False
 39            func_args = list(inspect.signature(obj).parameters.keys())
 40            text_from_docstring = getattr(obj, "__doc__", "")
 41            args_from_docstring = self._get_doc_params(text_from_docstring)
 42            if not args_from_docstring:
 43                return True
 44            names = [p[0] for p in args_from_docstring]
 45            types = [p[1] for p in args_from_docstring]
 46            if func_args != names:
 47                return False
 48            
 49            test_values = []
 50            for t in types:
 51                test_values.append(self._make_dummy_value(t))
 52            try:
 53                obj(*test_values)
 54            except TypeError:
 55                return False
 56            return True
 57        
 58        def _get_doc_params(self, text_from_docstring):
 59            if not text_from_docstring:
 60                return []
 61            lines = text_from_docstring.splitlines()
 62            start_of_Parameters = -1
 63            for i in range(len(lines)):
 64                if lines[i].strip() == "Parameters":
 65                    start_of_Parameters = i
 66                    break
 67            if start_of_Parameters == -1:
 68                return []
 69            curr = start_of_Parameters + 2
 70            result = []
 71            while curr < len(lines):
 72                line = lines[curr].strip()
 73                if line == "":
 74                    break
 75                if ":" in line:
 76                    parts = line.split(":")
 77                    name = parts[0].strip()
 78                    type_ = parts[1].strip()
 79                    result.append((name, type_))
 80                curr += 1
 81            return result
 82        
 83        def _make_dummy_value(self, type_str):
 84            type_str = type_str.strip()
 85
 86            if "|" in type_str:
 87                type_str = type_str.split("|")[0].strip()
 88
 89            if type_str.startswith("list"):
 90                return []
 91            if type_str.startswith("tuple"):
 92                return ()
 93            if type_str.startswith("set"):
 94                return set()
 95            if type_str.startswith("dict"):
 96                return {}
 97
 98            if type_str == "int":
 99                return 0
100            if type_str == "float":
101                return 0.0
102            if type_str == "str":
103                return ""
104            if type_str == "bool":
105                return False
106
107            return None
108        
109        def _check_hidden(self, obj):
110            for attr in dir(obj):
111                if attr.startswith("__") and attr.endswith("__"):
112                    continue
113                last_ch = None
114                for c in attr:
115                    if c.isalpha():
116                        last_ch = c
117                if not last_ch or not last_ch.isupper():
118                    continue
119                vowel = "aeiou"
120                count = 0
121                for c in attr.lower():
122                    if c in vowel:
123                        count += 1
124                        if count > 3:
125                            break
126                    else:
127                        count = 0
128                else:
129                    return True
130            return False    
131            
132    

EEEEEEEEEEEE.............
======================================================================
ERROR: test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues (test.TestBridgeKeeper.test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 55, in test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues
self.assertEqual(filtered.trailing_marker(7), 70)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: trailing_marker

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

======================================================================
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 20, in __getattr__
raise AttributeError(name)
AttributeError: score_map

======================================================================
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 20, in __getattr__
raise AttributeError(name)
AttributeError: triple_union_pair

======================================================================
ERROR: test_allows_set_typed_parameter (test.TestBridgeKeeper.test_allows_set_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 77, in test_allows_set_typed_parameter
self.assertEqual(filtered.gather_tags({"bridge", "keeper"}), "bridge,keeper")
^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: gather_tags

======================================================================
ERROR: test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder (test.TestBridgeKeeper.test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 64, in test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder
self.assertEqual(filtered.trailing_underscores(4), 5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: trailing_underscores

======================================================================
ERROR: test_allows_third_answer_with_single_uppercase_letter_name (test.TestBridgeKeeper.test_allows_third_answer_with_single_uppercase_letter_name)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 117, in test_allows_third_answer_with_single_uppercase_letter_name
self.assertEqual(filtered.single_letter_answer(5), 15)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: single_letter_answer

======================================================================
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 20, in __getattr__
raise AttributeError(name)
AttributeError: sum_group

======================================================================
ERROR: test_allows_valid_function (test.TestBridgeKeeper.test_allows_valid_function)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 9, in test_allows_valid_function
self.assertEqual(filtered.multiply_text(3, "na"), "nanana")
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: multiply_text

======================================================================
ERROR: test_allows_zero_arg_callable_when_parameters_block_is_missing (test.TestBridgeKeeper.test_allows_zero_arg_callable_when_parameters_block_is_missing)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 13, in test_allows_zero_arg_callable_when_parameters_block_is_missing
self.assertEqual(filtered.silent_oracle(), 42)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: silent_oracle

======================================================================
ERROR: test_allows_zero_arg_callable_with_missing_docstring (test.TestBridgeKeeper.test_allows_zero_arg_callable_with_missing_docstring)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 51, in test_allows_zero_arg_callable_with_missing_docstring
self.assertEqual(filtered.ghost_zero(), "boo")
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: ghost_zero

======================================================================
ERROR: test_ignores_parameter_like_lines_outside_parameters_block (test.TestBridgeKeeper.test_ignores_parameter_like_lines_outside_parameters_block)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 37, in test_ignores_parameter_like_lines_outside_parameters_block
self.assertEqual(filtered.tricky_doc(2, "xo"), "xoxo")
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 20, in __getattr__
raise AttributeError(name)
AttributeError: tricky_doc

----------------------------------------------------------------------
Ran 25 tests in 0.004s

FAILED (errors=12)

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

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