1"""Homework 4."""
2import importlib
3import itertools
4import re
5
6
7class BridgeKeeper:
8 """Brigde keeper class."""
9
10 def __init__(self, module_name):
11 self.module_name = module_name
12 self._module = None
13
14 def __enter__(self):
15 self._module = importlib.import_module(self.module_name)
16 return FilteredModule(self._module)
17
18 def __exit__(self, exc_type, exc_value, traceback):
19 return False
20
21
22class FilteredModule:
23 """Filter module class, which determinated which module is allowed."""
24
25 def __init__(self, module):
26 self._module = module
27 self._validator = ValidationHelperClass()
28
29 def __getattr__(self, name):
30 try:
31 attribute = getattr(self._module, name)
32 except AttributeError:
33 raise AttributeError(name) from None
34
35 if self._validator.is_module_allowed(attribute):
36 return attribute
37
38 raise AttributeError(name)
39
40
41class ValidationHelperClass:
42 """Helper validation class that contains all validation helper functions."""
43
44 BASIC_DUMMY_VALUES = {
45 "int": 1,
46 "float": 1.0,
47 "str": "dummy",
48 "bool": False,
49 "complex": 1 + 1j,
50 "bytes": b"dummy",
51 "None": None,
52 }
53
54 VALID_ATTRIBUTE_PATTERN = re.compile(
55 r"^(?!__)(?!.*[aeiouAEIOU]{4})[A-Za-z0-9_]*[A-Z][0-9_]*$"
56 )
57
58 PARAMETERS_PATTERN = re.compile(
59 r"Parameters\s*\n-+\s*\n([\s\S]*?)(?=\n\s*\n|$)"
60 )
61
62 @classmethod
63 def is_module_allowed(cls, candidate):
64 """ Method that checks id module is allowed per 3 conditions """
65 return (
66 cls.has_valid_name(candidate)
67 and cls.has_valid_attribute(candidate)
68 and cls.has_valid_quest(candidate)
69 )
70
71 @staticmethod
72 def has_valid_name(candidate):
73 """ First conditiona for valid name """
74 name = getattr(candidate, "__name__", None)
75
76 if not isinstance(name, str) or not name:
77 return False
78
79 return name[0].isupper()
80
81 @classmethod
82 def has_valid_attribute(cls, candidate):
83 """ Second condition for at least 1 valid attribute """
84 return any(
85 cls.VALID_ATTRIBUTE_PATTERN.search(attribute)
86 for attribute in dir(candidate)
87 )
88
89 @classmethod
90 def has_valid_quest(cls, candidate):
91 """ Third condition for valid params and doc params """
92 if not callable(candidate):
93 return False
94
95 doc = getattr(candidate, "__doc__", "") or ""
96
97 doc_parameters_match = re.search(cls.PARAMETERS_PATTERN, doc)
98
99 try:
100 if doc_parameters_match:
101 parameters = list(
102 cls._parse_doc_parameters(
103 doc_parameters_match.group(1).splitlines()
104 )
105 )
106 else:
107 parameters = []
108
109 dummy_args = [
110 cls._dummy_value_complex_structure(parameter_type)
111 for _, parameter_type in parameters
112 ]
113 except ValueError:
114 return False
115
116 for arguments in itertools.product(*dummy_args):
117 try:
118 candidate(*arguments)
119 except Exception:
120 return False
121
122 return True
123
124 @classmethod
125 def _parse_doc_parameters(cls, parameter_lines):
126 """ Parse doc parameters"""
127 for line in parameter_lines:
128 stripped_line = line.strip()
129
130 if not stripped_line:
131 break
132
133 if " : " not in stripped_line:
134 raise ValueError("Invalid parameter line")
135
136 name, parameter_type = stripped_line.split(":", 1)
137 yield name.strip(), parameter_type.strip()
138
139 @classmethod
140 def _dummy_value_complex_structure(cls, type_name):
141 """ Generate dummy values for complex structures """
142 union_parts = [part.strip() for part in type_name.split("|")]
143
144 if len(union_parts) > 1:
145 values = []
146
147 for part in union_parts:
148 values.extend(
149 cls._dummy_value_complex_structure(part)
150 )
151
152 return values
153
154 return cls._dummy_value_simple(type_name.strip())
155
156 @classmethod
157 def _dummy_value_simple(cls, type_name):
158 """ Generate dummy values simple structures """
159 if type_name in cls.BASIC_DUMMY_VALUES:
160 return [cls.BASIC_DUMMY_VALUES[type_name]]
161
162 list_match = re.fullmatch(r"list\[(.+)\]", type_name)
163 if list_match:
164 inner_type = list_match.group(1).strip()
165 return [
166 [value]
167 for value in cls._dummy_value_complex_structure(inner_type)
168 ]
169 tuple_match = re.fullmatch(r"tuple\[(.+)\]", type_name)
170 if tuple_match:
171 inner_type = tuple_match.group(1).strip()
172 return [
173 (value,)
174 for value in cls._dummy_value_complex_structure(inner_type)
175 ]
176
177 set_match = re.fullmatch(r"set\[(.+)\]", type_name)
178 if set_match:
179 inner_type = set_match.group(1).strip()
180 values = []
181
182 for value in cls._dummy_value_complex_structure(inner_type):
183 try:
184 values.append({value})
185 except TypeError:
186 continue
187
188 if not values:
189 raise ValueError("Invalid set inner type")
190
191 return values
192
193 dict_match = re.fullmatch(r"dict\[(.+),\s*(.+)\]", type_name)
194 if dict_match:
195 key_type = dict_match.group(1).strip()
196 value_type = dict_match.group(2).strip()
197
198 keys = cls._dummy_value_complex_structure(key_type)
199 values = cls._dummy_value_complex_structure(value_type)
200
201 result = []
202
203 for key in keys:
204 for value in values:
205 try:
206 result.append({key: value})
207 except TypeError:
208 continue
209
210 if not result:
211 raise ValueError("Invalid dict key type")
212
213 return result
214
215 raise ValueError(f"Invalid type: {type_name}")
............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
----------------------------------------------------------------------
Ran 25 tests in 0.002s
FAILED (failures=1)
01.05.2026 15:51
01.05.2026 15:53
01.05.2026 15:54
01.05.2026 15:59