1import ast
2import inspect
3import re
4import sys
5from types import ModuleType
6from typing import Any
7
8
9class BridgeKeeper:
10 def __init__(self, module_name) -> None:
11 self.module_name = module_name
12
13 @staticmethod
14 def _check_for_attributes(obj: Any) -> bool:
15 return bool([arg for arg in dir(obj) if (not re.match(r"[aeiou]{4,}", arg) and
16 not re.match(r"^__.+__$", arg) and
17 not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower())])
18
19 @staticmethod
20 def _check_for_name(obj: Any) -> bool:
21 return "__name__" in dir(obj) and obj.__name__[0].isupper()
22
23 @staticmethod
24 def _check_for_quest(obj: Any) -> bool:
25
26 def convert_doctype(doctype: str) -> object:
27 base_types = {
28 "int": 1,
29 "float": 1.2,
30 "str": "'string'",
31 "bool": True,
32 }
33
34 if not doctype.startswith('dict'):
35 doctype = doctype.replace("[", "((")
36 doctype = doctype.replace("]", ",))")
37 else:
38 doctype = doctype.replace("[", "([(")
39 doctype = doctype.replace("]", ")])")
40 for key, value in base_types.items():
41 doctype = doctype.replace(key, str(value))
42
43 return ast.literal_eval(doctype)
44
45 func_params = inspect.signature(obj).parameters.keys()
46 doc_string = obj.__doc__
47 doc_params = re.search(r"(?s).+(?<=Parameters\n).+(?<=-{10}\n)(.+?)(?=\n\n|\n$|$)",
48 "\n".join([x.strip() for x in doc_string.split("\n")]))
49 test_args = [[]]
50 if doc_params:
51 for name, types in [x.split(" : ") for x in doc_params.group(1).split("\n") if " : " in x]:
52 if name not in func_params:
53 return False
54 test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
55
56 try:
57 for args in test_args:
58 obj(*args)
59 return True
60 except Exception:
61 return False
62
63 def __enter__(self) -> ModuleType:
64 module = __import__(self.module_name)
65 copy_module = ModuleType("copy_module")
66 for obj_name, obj in [(obj_name, getattr(module, obj_name)) for obj_name in dir(module) if
67 callable(getattr(module, obj_name))]:
68 if (self._check_for_name(obj) and
69 self._check_for_attributes(obj) and
70 self._check_for_quest(obj)):
71 setattr(copy_module, obj_name, obj)
72 return copy_module
73
74 def __exit__(self, exc_type, exc, tb):
75 del sys.modules[self.module_name]
76
77
78if __name__ == "__main__":
79 with BridgeKeeper("tests") as filtered_module:
80 # print.pprint(sys.modules)
81 # print(filtered_module.baba(5, 'banichka'))
82 # print(filtered_module.dyado()) # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3
83 filtered_module.strinka # Хвърля се AttributeError, защото strinka не може
84 # да бъде извикана успешно с аргументите, описани в docstring-а
85 pass
EEEEEEEEEEEEEEEEEEEEEEEEE
======================================================================
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 54, in test_allows_attribute_whose_last_letter_is_uppercase_but_name_continues
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_allows_callable_instance (test.TestBridgeKeeper.test_allows_callable_instance)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 85, in test_allows_callable_instance
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_allows_dict_typed_parameter (test.TestBridgeKeeper.test_allows_dict_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 67, in test_allows_dict_typed_parameter
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
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 94, in test_allows_multi_argument_union_bonus_case
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_allows_set_typed_parameter (test.TestBridgeKeeper.test_allows_set_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 76, in test_allows_set_typed_parameter
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
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 63, in test_allows_third_answer_name_with_trailing_double_underscores_if_not_dunder
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
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 116, in test_allows_third_answer_with_single_uppercase_letter_name
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_allows_union_typed_parameter (test.TestBridgeKeeper.test_allows_union_typed_parameter)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 16, in test_allows_union_typed_parameter
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_allows_valid_function (test.TestBridgeKeeper.test_allows_valid_function)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 8, in test_allows_valid_function
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
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 12, in test_allows_zero_arg_callable_when_parameters_block_is_missing
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
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 50, in test_allows_zero_arg_callable_with_missing_docstring
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
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 36, in test_ignores_parameter_like_lines_outside_parameters_block
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: 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 58, in test_rejects_callable_when_parameter_names_do_not_match
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_callable_without_valid_third_answer (test.TestBridgeKeeper.test_rejects_callable_without_valid_third_answer)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 31, in test_rejects_callable_without_valid_third_answer
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_dict_when_callable_does_not_work_with_documented_key_and_value_types (test.TestBridgeKeeper.test_rejects_dict_when_callable_does_not_work_with_documented_key_and_value_types)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 89, in test_rejects_dict_when_callable_does_not_work_with_documented_key_and_value_types
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_docstring_with_arity_mismatch (test.TestBridgeKeeper.test_rejects_docstring_with_arity_mismatch)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 45, in test_rejects_docstring_with_arity_mismatch
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_docstring_with_parameter_order_mismatch (test.TestBridgeKeeper.test_rejects_docstring_with_parameter_order_mismatch)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 40, in test_rejects_docstring_with_parameter_order_mismatch
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_list_when_callable_does_not_work_with_documented_element_type (test.TestBridgeKeeper.test_rejects_list_when_callable_does_not_work_with_documented_element_type)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 101, in test_rejects_list_when_callable_does_not_work_with_documented_element_type
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_missing_parameters_block_when_callable_requires_arguments (test.TestBridgeKeeper.test_rejects_missing_parameters_block_when_callable_requires_arguments)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 80, in test_rejects_missing_parameters_block_when_callable_requires_arguments
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_non_callable_object (test.TestBridgeKeeper.test_rejects_non_callable_object)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 26, in test_rejects_non_callable_object
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_object_with_lowercase_name (test.TestBridgeKeeper.test_rejects_object_with_lowercase_name)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 21, in test_rejects_object_with_lowercase_name
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_set_when_callable_does_not_work_with_documented_element_type (test.TestBridgeKeeper.test_rejects_set_when_callable_does_not_work_with_documented_element_type)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 111, in test_rejects_set_when_callable_does_not_work_with_documented_element_type
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_third_answer_with_four_consecutive_uppercase_vowels (test.TestBridgeKeeper.test_rejects_third_answer_with_four_consecutive_uppercase_vowels)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 120, in test_rejects_third_answer_with_four_consecutive_uppercase_vowels
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: test_rejects_tuple_when_callable_does_not_work_with_documented_element_type (test.TestBridgeKeeper.test_rejects_tuple_when_callable_does_not_work_with_documented_element_type)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 106, in test_rejects_tuple_when_callable_does_not_work_with_documented_element_type
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
======================================================================
ERROR: 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 71, in test_rejects_union_when_callable_does_not_support_all_union_branches
with BridgeKeeper("bridgekeeper_cases") as filtered:
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __enter__
self._check_for_quest(obj)):
~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/tmp/solution.py", line 54, in _check_for_quest
test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args]
~~~~~~~~~~~~~~~^^^^^^^
File "/tmp/solution.py", line 43, in convert_doctype
return ast.literal_eval(doctype)
~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.14/ast.py", line 106, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.14/ast.py", line 105, in _convert
return _convert_signed_num(node)
File "/usr/lib/python3.14/ast.py", line 79, in _convert_signed_num
return _convert_num(node)
File "/usr/lib/python3.14/ast.py", line 70, in _convert_num
_raise_malformed_node(node)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/ast.py", line 67, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: Call(func=Name(id='list', ctx=Load()), args=[Tuple(elts=[Constant(value=1, kind=None)], ctx=Load())], keywords=[])
----------------------------------------------------------------------
Ran 25 tests in 0.026s
FAILED (errors=25)
| f | 1 | import ast | f | 1 | import ast |
| 2 | import inspect | 2 | import inspect | ||
| 3 | import re | 3 | import re | ||
| n | n | 4 | import sys | ||
| 4 | from types import ModuleType | 5 | from types import ModuleType | ||
| n | n | 6 | from typing import Any | ||
| 5 | 7 | ||||
| 6 | 8 | ||||
| 7 | class BridgeKeeper: | 9 | class BridgeKeeper: | ||
| 8 | def __init__(self, module_name) -> None: | 10 | def __init__(self, module_name) -> None: | ||
| 9 | self.module_name = module_name | 11 | self.module_name = module_name | ||
| 10 | 12 | ||||
| 11 | @staticmethod | 13 | @staticmethod | ||
| n | 12 | def _check_for_attributes(obj) -> bool: | n | 14 | def _check_for_attributes(obj: Any) -> bool: |
| 13 | for arg in obj.__dir__(): | 15 | return bool([arg for arg in dir(obj) if (not re.match(r"[aeiou]{4,}", arg) and | ||
| 14 | if (not re.match(r"[aeiou]{4,}", arg) and | ||||
| 15 | not re.match(r"^__.+__$", arg) and | 16 | not re.match(r"^__.+__$", arg) and | ||
| 16 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower()): | 17 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower())]) | ||
| 17 | return True | ||||
| 18 | return False | ||||
| 19 | 18 | ||||
| 20 | @staticmethod | 19 | @staticmethod | ||
| n | 21 | def _check_for_name(obj) -> bool: | n | 20 | def _check_for_name(obj: Any) -> bool: |
| 22 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | 21 | return "__name__" in dir(obj) and obj.__name__[0].isupper() | ||
| 23 | 22 | ||||
| 24 | @staticmethod | 23 | @staticmethod | ||
| n | 25 | def _check_for_quest(obj) -> bool: | n | 24 | def _check_for_quest(obj: Any) -> bool: |
| 26 | 25 | ||||
| 27 | def convert_doctype(doctype: str) -> object: | 26 | def convert_doctype(doctype: str) -> object: | ||
| n | 28 | help_values = { | n | 27 | base_types = { |
| 29 | "int": 1, | 28 | "int": 1, | ||
| 30 | "float": 1.2, | 29 | "float": 1.2, | ||
| 31 | "str": "'string'", | 30 | "str": "'string'", | ||
| 32 | "bool": True, | 31 | "bool": True, | ||
| 33 | } | 32 | } | ||
| 34 | 33 | ||||
| 35 | if not doctype.startswith('dict'): | 34 | if not doctype.startswith('dict'): | ||
| 36 | doctype = doctype.replace("[", "((") | 35 | doctype = doctype.replace("[", "((") | ||
| 37 | doctype = doctype.replace("]", ",))") | 36 | doctype = doctype.replace("]", ",))") | ||
| 38 | else: | 37 | else: | ||
| 39 | doctype = doctype.replace("[", "([(") | 38 | doctype = doctype.replace("[", "([(") | ||
| 40 | doctype = doctype.replace("]", ")])") | 39 | doctype = doctype.replace("]", ")])") | ||
| n | 41 | for key, value in help_values.items(): | n | 40 | for key, value in base_types.items(): |
| 42 | doctype = doctype.replace(key, str(value)) | 41 | doctype = doctype.replace(key, str(value)) | ||
| 43 | 42 | ||||
| 44 | return ast.literal_eval(doctype) | 43 | return ast.literal_eval(doctype) | ||
| 45 | 44 | ||||
| n | 46 | if "__call__" in dir(obj): | n | 45 | func_params = inspect.signature(obj).parameters.keys() |
| 47 | doc_string = obj.__doc__ | 46 | doc_string = obj.__doc__ | ||
| 48 | if inspect.isfunction(obj): | ||||
| 49 | func_args = obj.__code__.co_varnames | ||||
| 50 | else: | ||||
| 51 | func_args = obj.__init__.__code__.co_varnames | ||||
| 52 | else: | ||||
| 53 | return False | ||||
| 54 | |||||
| 55 | doc_args = re.search(r"(?s)(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", | 47 | doc_params = re.search(r"(?s).+(?<=Parameters\n).+(?<=-{10}\n)(.+?)(?=\n\n|\n$|$)", | ||
| 56 | "\n".join(list(map(lambda x: x.strip(), doc_string.split("\n"))))) | 48 | "\n".join([x.strip() for x in doc_string.split("\n")])) | ||
| 57 | test_params = [[]] | 49 | test_args = [[]] | ||
| 58 | if doc_args: | 50 | if doc_params: | ||
| 59 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | 51 | for name, types in [x.split(" : ") for x in doc_params.group(1).split("\n") if " : " in x]: | ||
| 60 | kvp = arg.split(" : ") | ||||
| 61 | name, types = kvp | ||||
| 62 | if name not in func_args: | 52 | if name not in func_params: | ||
| 63 | return False | 53 | return False | ||
| n | 64 | types = types.split(" | ") | n | ||
| 65 | test_params = [test + [convert_doctype(_type)] for _type in types for test in test_params] | 54 | test_args = [args + [convert_doctype(_type)] for _type in types.split(" | ") for args in test_args] | ||
| 66 | 55 | ||||
| 67 | try: | 56 | try: | ||
| n | 68 | for params in test_params: | n | 57 | for args in test_args: |
| 69 | obj(*params) | 58 | obj(*args) | ||
| 70 | except (ValueError, TypeError): | 59 | return True | ||
| 60 | except Exception: | ||||
| 71 | return False | 61 | return False | ||
| n | 72 | n | |||
| 73 | return True | ||||
| 74 | 62 | ||||
| 75 | def __enter__(self) -> ModuleType: | 63 | def __enter__(self) -> ModuleType: | ||
| 76 | module = __import__(self.module_name) | 64 | module = __import__(self.module_name) | ||
| n | 77 | for obj_name in module.__dir__(): | n | 65 | copy_module = ModuleType("copy_module") |
| 78 | obj = getattr(module, obj_name) | 66 | for obj_name, obj in [(obj_name, getattr(module, obj_name)) for obj_name in dir(module) if | ||
| 79 | if "__call__" in obj.__dir__() and (not self._check_for_name(obj) or | 67 | callable(getattr(module, obj_name))]: | ||
| 80 | not self._check_for_attributes(obj) or | 68 | if (self._check_for_name(obj) and | ||
| 69 | self._check_for_attributes(obj) and | ||||
| 81 | not self._check_for_quest(obj)): | 70 | self._check_for_quest(obj)): | ||
| 82 | delattr(module, obj_name) | 71 | setattr(copy_module, obj_name, obj) | ||
| 83 | return module | 72 | return copy_module | ||
| 84 | 73 | ||||
| 85 | def __exit__(self, exc_type, exc, tb): | 74 | def __exit__(self, exc_type, exc, tb): | ||
| n | 86 | pass | n | 75 | del sys.modules[self.module_name] |
| 87 | 76 | ||||
| 88 | 77 | ||||
| 89 | if __name__ == "__main__": | 78 | if __name__ == "__main__": | ||
| 90 | with BridgeKeeper("tests") as filtered_module: | 79 | with BridgeKeeper("tests") as filtered_module: | ||
| t | t | 80 | # print.pprint(sys.modules) | ||
| 91 | print(filtered_module.baba(5, 'banichka')) | 81 | # print(filtered_module.baba(5, 'banichka')) | ||
| 92 | filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | 82 | # print(filtered_module.dyado()) # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | ||
| 93 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | 83 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може | ||
| 84 | # да бъде извикана успешно с аргументите, описани в docstring-а | ||||
| 94 | pass | 85 | pass |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| n | n | 1 | import ast | ||
| 2 | import inspect | ||||
| 1 | import re | 3 | import re | ||
| n | 2 | import inspect | n | 4 | from types import ModuleType |
| 3 | from itertools import permutations | 5 | |||
| 4 | 6 | ||||
| 5 | class BridgeKeeper: | 7 | class BridgeKeeper: | ||
| 6 | def __init__(self, module_name) -> None: | 8 | def __init__(self, module_name) -> None: | ||
| 7 | self.module_name = module_name | 9 | self.module_name = module_name | ||
| 8 | 10 | ||||
| 9 | @staticmethod | 11 | @staticmethod | ||
| n | 10 | def __check_for_attributes(obj) -> bool: | n | 12 | def _check_for_attributes(obj) -> bool: |
| 11 | for arg in obj.__dir__(): | 13 | for arg in obj.__dir__(): | ||
| n | 12 | if (not re.match(r"[aeiou]{4,}", arg) and | n | 14 | if (not re.match(r"[aeiou]{4,}", arg) and |
| 13 | not re.match(r"^__.+__$", arg) and | 15 | not re.match(r"^__.+__$", arg) and | ||
| 14 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower()): | 16 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower()): | ||
| 15 | return True | 17 | return True | ||
| 16 | return False | 18 | return False | ||
| 17 | 19 | ||||
| 18 | @staticmethod | 20 | @staticmethod | ||
| n | 19 | def __check_for_name(obj) -> bool: | n | 21 | def _check_for_name(obj) -> bool: |
| 20 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | 22 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | ||
| n | 21 | n | 23 | ||
| 22 | @staticmethod | 24 | @staticmethod | ||
| n | 23 | def __check_for_quest(obj) -> bool: | n | 25 | def _check_for_quest(obj) -> bool: |
| 24 | 26 | ||||
| 25 | def convert_doctype(doctype: str) -> object: | 27 | def convert_doctype(doctype: str) -> object: | ||
| 26 | help_values = { | 28 | help_values = { | ||
| n | 27 | "int": 1, | n | 29 | "int": 1, |
| 28 | "float": 1.2, | 30 | "float": 1.2, | ||
| 29 | "str": "'string'", | 31 | "str": "'string'", | ||
| 30 | "bool": True, | 32 | "bool": True, | ||
| 31 | } | 33 | } | ||
| 32 | 34 | ||||
| 33 | if not doctype.startswith('dict'): | 35 | if not doctype.startswith('dict'): | ||
| 34 | doctype = doctype.replace("[", "((") | 36 | doctype = doctype.replace("[", "((") | ||
| 35 | doctype = doctype.replace("]", ",))") | 37 | doctype = doctype.replace("]", ",))") | ||
| 36 | else: | 38 | else: | ||
| 37 | doctype = doctype.replace("[", "([(") | 39 | doctype = doctype.replace("[", "([(") | ||
| 38 | doctype = doctype.replace("]", ")])") | 40 | doctype = doctype.replace("]", ")])") | ||
| n | 39 | for type, value in help_values.items(): | n | 41 | for key, value in help_values.items(): |
| 40 | doctype = doctype.replace(type, str(value)) | 42 | doctype = doctype.replace(key, str(value)) | ||
| 41 | 43 | ||||
| 42 | return eval(doctype) | 44 | return ast.literal_eval(doctype) | ||
| 43 | 45 | ||||
| 44 | if "__call__" in dir(obj): | 46 | if "__call__" in dir(obj): | ||
| 45 | doc_string = obj.__doc__ | 47 | doc_string = obj.__doc__ | ||
| 46 | if inspect.isfunction(obj): | 48 | if inspect.isfunction(obj): | ||
| 47 | func_args = obj.__code__.co_varnames | 49 | func_args = obj.__code__.co_varnames | ||
| 48 | else: | 50 | else: | ||
| 49 | func_args = obj.__init__.__code__.co_varnames | 51 | func_args = obj.__init__.__code__.co_varnames | ||
| 50 | else: | 52 | else: | ||
| 51 | return False | 53 | return False | ||
| n | 52 | n | 54 | ||
| 53 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | 55 | doc_args = re.search(r"(?s)(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", | ||
| 56 | "\n".join(list(map(lambda x: x.strip(), doc_string.split("\n"))))) | ||||
| 54 | test_params = [[]] | 57 | test_params = [[]] | ||
| 55 | if doc_args: | 58 | if doc_args: | ||
| 56 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | 59 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | ||
| 57 | kvp = arg.split(" : ") | 60 | kvp = arg.split(" : ") | ||
| 58 | name, types = kvp | 61 | name, types = kvp | ||
| 59 | if name not in func_args: | 62 | if name not in func_args: | ||
| 60 | return False | 63 | return False | ||
| 61 | types = types.split(" | ") | 64 | types = types.split(" | ") | ||
| n | 62 | test_params = [test + [convert_doctype(type)] for type in types for test in test_params] | n | 65 | test_params = [test + [convert_doctype(_type)] for _type in types for test in test_params] |
| 63 | 66 | ||||
| 64 | try: | 67 | try: | ||
| 65 | for params in test_params: | 68 | for params in test_params: | ||
| 66 | obj(*params) | 69 | obj(*params) | ||
| n | 67 | except: | n | 70 | except (ValueError, TypeError): |
| 68 | return False | 71 | return False | ||
| 69 | 72 | ||||
| 70 | return True | 73 | return True | ||
| n | 71 | n | 74 | ||
| 72 | def __enter__(self): | 75 | def __enter__(self) -> ModuleType: | ||
| 73 | module = __import__(self.module_name) | 76 | module = __import__(self.module_name) | ||
| 74 | for obj_name in module.__dir__(): | 77 | for obj_name in module.__dir__(): | ||
| 75 | obj = getattr(module, obj_name) | 78 | obj = getattr(module, obj_name) | ||
| n | 76 | if (not self.__check_for_name(obj) or | n | 79 | if "__call__" in obj.__dir__() and (not self._check_for_name(obj) or |
| 77 | not self.__check_for_attributes(obj) or | 80 | not self._check_for_attributes(obj) or | ||
| 78 | not self.__check_for_quest(obj)): | 81 | not self._check_for_quest(obj)): | ||
| 79 | delattr(module, obj_name) | 82 | delattr(module, obj_name) | ||
| 80 | return module | 83 | return module | ||
| 81 | 84 | ||||
| 82 | def __exit__(self, exc_type, exc, tb): | 85 | def __exit__(self, exc_type, exc, tb): | ||
| 83 | pass | 86 | pass | ||
| 84 | 87 | ||||
| 85 | 88 | ||||
| 86 | if __name__ == "__main__": | 89 | if __name__ == "__main__": | ||
| 87 | with BridgeKeeper("tests") as filtered_module: | 90 | with BridgeKeeper("tests") as filtered_module: | ||
| t | 88 | filtered_module.baba(5, 'banichka') | t | 91 | print(filtered_module.baba(5, 'banichka')) |
| 89 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | 92 | filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | ||
| 90 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | 93 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | ||
| 91 | pass | 94 | pass |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | import inspect | 2 | import inspect | ||
| n | n | 3 | from itertools import permutations | ||
| 3 | 4 | ||||
| 4 | class BridgeKeeper: | 5 | class BridgeKeeper: | ||
| 5 | def __init__(self, module_name) -> None: | 6 | def __init__(self, module_name) -> None: | ||
| 6 | self.module_name = module_name | 7 | self.module_name = module_name | ||
| 7 | 8 | ||||
| 8 | @staticmethod | 9 | @staticmethod | ||
| 9 | def __check_for_attributes(obj) -> bool: | 10 | def __check_for_attributes(obj) -> bool: | ||
| 10 | for arg in obj.__dir__(): | 11 | for arg in obj.__dir__(): | ||
| 11 | if (not re.match(r"[aeiou]{4,}", arg) and | 12 | if (not re.match(r"[aeiou]{4,}", arg) and | ||
| 12 | not re.match(r"^__.+__$", arg) and | 13 | not re.match(r"^__.+__$", arg) and | ||
| 13 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower()): | 14 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower()): | ||
| 14 | return True | 15 | return True | ||
| 15 | return False | 16 | return False | ||
| 16 | 17 | ||||
| 17 | @staticmethod | 18 | @staticmethod | ||
| 18 | def __check_for_name(obj) -> bool: | 19 | def __check_for_name(obj) -> bool: | ||
| 19 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | 20 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | ||
| 20 | 21 | ||||
| 21 | @staticmethod | 22 | @staticmethod | ||
| 22 | def __check_for_quest(obj) -> bool: | 23 | def __check_for_quest(obj) -> bool: | ||
| 23 | 24 | ||||
| n | 24 | def convert_doctype_to_type(doctype: str) -> object: | n | 25 | def convert_doctype(doctype: str) -> object: |
| 25 | help_values = { | 26 | help_values = { | ||
| 26 | "int": 1, | 27 | "int": 1, | ||
| 27 | "float": 1.2, | 28 | "float": 1.2, | ||
| 28 | "str": "'string'", | 29 | "str": "'string'", | ||
| 29 | "bool": True, | 30 | "bool": True, | ||
| 30 | } | 31 | } | ||
| 31 | 32 | ||||
| 32 | if not doctype.startswith('dict'): | 33 | if not doctype.startswith('dict'): | ||
| 33 | doctype = doctype.replace("[", "((") | 34 | doctype = doctype.replace("[", "((") | ||
| 34 | doctype = doctype.replace("]", ",))") | 35 | doctype = doctype.replace("]", ",))") | ||
| 35 | else: | 36 | else: | ||
| 36 | doctype = doctype.replace("[", "([(") | 37 | doctype = doctype.replace("[", "([(") | ||
| 37 | doctype = doctype.replace("]", ")])") | 38 | doctype = doctype.replace("]", ")])") | ||
| 38 | for type, value in help_values.items(): | 39 | for type, value in help_values.items(): | ||
| 39 | doctype = doctype.replace(type, str(value)) | 40 | doctype = doctype.replace(type, str(value)) | ||
| 40 | 41 | ||||
| 41 | return eval(doctype) | 42 | return eval(doctype) | ||
| 42 | 43 | ||||
| 43 | if "__call__" in dir(obj): | 44 | if "__call__" in dir(obj): | ||
| 44 | doc_string = obj.__doc__ | 45 | doc_string = obj.__doc__ | ||
| 45 | if inspect.isfunction(obj): | 46 | if inspect.isfunction(obj): | ||
| 46 | func_args = obj.__code__.co_varnames | 47 | func_args = obj.__code__.co_varnames | ||
| 47 | else: | 48 | else: | ||
| 48 | func_args = obj.__init__.__code__.co_varnames | 49 | func_args = obj.__init__.__code__.co_varnames | ||
| 49 | else: | 50 | else: | ||
| 50 | return False | 51 | return False | ||
| 51 | 52 | ||||
| 52 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | 53 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | ||
| 53 | test_params = [[]] | 54 | test_params = [[]] | ||
| 54 | if doc_args: | 55 | if doc_args: | ||
| 55 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | 56 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | ||
| 56 | kvp = arg.split(" : ") | 57 | kvp = arg.split(" : ") | ||
| 57 | name, types = kvp | 58 | name, types = kvp | ||
| 58 | if name not in func_args: | 59 | if name not in func_args: | ||
| 59 | return False | 60 | return False | ||
| 60 | types = types.split(" | ") | 61 | types = types.split(" | ") | ||
| t | 61 | test_params *= len(types) | t | 62 | test_params = [test + [convert_doctype(type)] for type in types for test in test_params] |
| 62 | for i, type in enumerate(types): | ||||
| 63 | test_params[i].append(convert_doctype_to_type(type)) | ||||
| 64 | 63 | ||||
| 65 | try: | 64 | try: | ||
| 66 | for params in test_params: | 65 | for params in test_params: | ||
| 67 | obj(*params) | 66 | obj(*params) | ||
| 68 | except: | 67 | except: | ||
| 69 | return False | 68 | return False | ||
| 70 | 69 | ||||
| 71 | return True | 70 | return True | ||
| 72 | 71 | ||||
| 73 | def __enter__(self): | 72 | def __enter__(self): | ||
| 74 | module = __import__(self.module_name) | 73 | module = __import__(self.module_name) | ||
| 75 | for obj_name in module.__dir__(): | 74 | for obj_name in module.__dir__(): | ||
| 76 | obj = getattr(module, obj_name) | 75 | obj = getattr(module, obj_name) | ||
| 77 | if (not self.__check_for_name(obj) or | 76 | if (not self.__check_for_name(obj) or | ||
| 78 | not self.__check_for_attributes(obj) or | 77 | not self.__check_for_attributes(obj) or | ||
| 79 | not self.__check_for_quest(obj)): | 78 | not self.__check_for_quest(obj)): | ||
| 80 | delattr(module, obj_name) | 79 | delattr(module, obj_name) | ||
| 81 | return module | 80 | return module | ||
| 82 | 81 | ||||
| 83 | def __exit__(self, exc_type, exc, tb): | 82 | def __exit__(self, exc_type, exc, tb): | ||
| 84 | pass | 83 | pass | ||
| 85 | 84 | ||||
| 86 | 85 | ||||
| 87 | if __name__ == "__main__": | 86 | if __name__ == "__main__": | ||
| 88 | with BridgeKeeper("tests") as filtered_module: | 87 | with BridgeKeeper("tests") as filtered_module: | ||
| 89 | filtered_module.baba(5, 'banichka') | 88 | filtered_module.baba(5, 'banichka') | ||
| 90 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | 89 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | ||
| 91 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | 90 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | ||
| 92 | pass | 91 | pass |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | import inspect | 2 | import inspect | ||
| 3 | 3 | ||||
| 4 | class BridgeKeeper: | 4 | class BridgeKeeper: | ||
| 5 | def __init__(self, module_name) -> None: | 5 | def __init__(self, module_name) -> None: | ||
| 6 | self.module_name = module_name | 6 | self.module_name = module_name | ||
| 7 | 7 | ||||
| 8 | @staticmethod | 8 | @staticmethod | ||
| 9 | def __check_for_attributes(obj) -> bool: | 9 | def __check_for_attributes(obj) -> bool: | ||
| 10 | for arg in obj.__dir__(): | 10 | for arg in obj.__dir__(): | ||
| 11 | if (not re.match(r"[aeiou]{4,}", arg) and | 11 | if (not re.match(r"[aeiou]{4,}", arg) and | ||
| 12 | not re.match(r"^__.+__$", arg) and | 12 | not re.match(r"^__.+__$", arg) and | ||
| n | 13 | list(filter(lambda x: x.isalpha(), list(arg)))[-1].isupper()): | n | 13 | not list(filter(lambda x: x.isalpha(), list(arg)))[-1].islower()): |
| 14 | return True | 14 | return True | ||
| 15 | return False | 15 | return False | ||
| 16 | 16 | ||||
| 17 | @staticmethod | 17 | @staticmethod | ||
| 18 | def __check_for_name(obj) -> bool: | 18 | def __check_for_name(obj) -> bool: | ||
| 19 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | 19 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | ||
| 20 | 20 | ||||
| 21 | @staticmethod | 21 | @staticmethod | ||
| 22 | def __check_for_quest(obj) -> bool: | 22 | def __check_for_quest(obj) -> bool: | ||
| 23 | 23 | ||||
| 24 | def convert_doctype_to_type(doctype: str) -> object: | 24 | def convert_doctype_to_type(doctype: str) -> object: | ||
| 25 | help_values = { | 25 | help_values = { | ||
| 26 | "int": 1, | 26 | "int": 1, | ||
| 27 | "float": 1.2, | 27 | "float": 1.2, | ||
| 28 | "str": "'string'", | 28 | "str": "'string'", | ||
| 29 | "bool": True, | 29 | "bool": True, | ||
| 30 | } | 30 | } | ||
| 31 | 31 | ||||
| 32 | if not doctype.startswith('dict'): | 32 | if not doctype.startswith('dict'): | ||
| 33 | doctype = doctype.replace("[", "((") | 33 | doctype = doctype.replace("[", "((") | ||
| 34 | doctype = doctype.replace("]", ",))") | 34 | doctype = doctype.replace("]", ",))") | ||
| 35 | else: | 35 | else: | ||
| 36 | doctype = doctype.replace("[", "([(") | 36 | doctype = doctype.replace("[", "([(") | ||
| 37 | doctype = doctype.replace("]", ")])") | 37 | doctype = doctype.replace("]", ")])") | ||
| 38 | for type, value in help_values.items(): | 38 | for type, value in help_values.items(): | ||
| 39 | doctype = doctype.replace(type, str(value)) | 39 | doctype = doctype.replace(type, str(value)) | ||
| 40 | 40 | ||||
| 41 | return eval(doctype) | 41 | return eval(doctype) | ||
| 42 | 42 | ||||
| 43 | if "__call__" in dir(obj): | 43 | if "__call__" in dir(obj): | ||
| 44 | doc_string = obj.__doc__ | 44 | doc_string = obj.__doc__ | ||
| 45 | if inspect.isfunction(obj): | 45 | if inspect.isfunction(obj): | ||
| 46 | func_args = obj.__code__.co_varnames | 46 | func_args = obj.__code__.co_varnames | ||
| 47 | else: | 47 | else: | ||
| 48 | func_args = obj.__init__.__code__.co_varnames | 48 | func_args = obj.__init__.__code__.co_varnames | ||
| 49 | else: | 49 | else: | ||
| 50 | return False | 50 | return False | ||
| 51 | 51 | ||||
| 52 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | 52 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | ||
| 53 | test_params = [[]] | 53 | test_params = [[]] | ||
| 54 | if doc_args: | 54 | if doc_args: | ||
| 55 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | 55 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | ||
| 56 | kvp = arg.split(" : ") | 56 | kvp = arg.split(" : ") | ||
| 57 | name, types = kvp | 57 | name, types = kvp | ||
| 58 | if name not in func_args: | 58 | if name not in func_args: | ||
| 59 | return False | 59 | return False | ||
| 60 | types = types.split(" | ") | 60 | types = types.split(" | ") | ||
| 61 | test_params *= len(types) | 61 | test_params *= len(types) | ||
| 62 | for i, type in enumerate(types): | 62 | for i, type in enumerate(types): | ||
| 63 | test_params[i].append(convert_doctype_to_type(type)) | 63 | test_params[i].append(convert_doctype_to_type(type)) | ||
| t | 64 | elif not func_args: | t | ||
| 65 | return True | ||||
| 66 | 64 | ||||
| 67 | try: | 65 | try: | ||
| 68 | for params in test_params: | 66 | for params in test_params: | ||
| 69 | obj(*params) | 67 | obj(*params) | ||
| 70 | except: | 68 | except: | ||
| 71 | return False | 69 | return False | ||
| 72 | 70 | ||||
| 73 | return True | 71 | return True | ||
| 74 | 72 | ||||
| 75 | def __enter__(self): | 73 | def __enter__(self): | ||
| 76 | module = __import__(self.module_name) | 74 | module = __import__(self.module_name) | ||
| 77 | for obj_name in module.__dir__(): | 75 | for obj_name in module.__dir__(): | ||
| 78 | obj = getattr(module, obj_name) | 76 | obj = getattr(module, obj_name) | ||
| 79 | if (not self.__check_for_name(obj) or | 77 | if (not self.__check_for_name(obj) or | ||
| 80 | not self.__check_for_attributes(obj) or | 78 | not self.__check_for_attributes(obj) or | ||
| 81 | not self.__check_for_quest(obj)): | 79 | not self.__check_for_quest(obj)): | ||
| 82 | delattr(module, obj_name) | 80 | delattr(module, obj_name) | ||
| 83 | return module | 81 | return module | ||
| 84 | 82 | ||||
| 85 | def __exit__(self, exc_type, exc, tb): | 83 | def __exit__(self, exc_type, exc, tb): | ||
| 86 | pass | 84 | pass | ||
| 87 | 85 | ||||
| 88 | 86 | ||||
| 89 | if __name__ == "__main__": | 87 | if __name__ == "__main__": | ||
| 90 | with BridgeKeeper("tests") as filtered_module: | 88 | with BridgeKeeper("tests") as filtered_module: | ||
| 91 | filtered_module.baba(5, 'banichka') | 89 | filtered_module.baba(5, 'banichka') | ||
| 92 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | 90 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | ||
| 93 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | 91 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | ||
| 94 | pass | 92 | pass |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | import inspect | 2 | import inspect | ||
| 3 | 3 | ||||
| 4 | class BridgeKeeper: | 4 | class BridgeKeeper: | ||
| 5 | def __init__(self, module_name) -> None: | 5 | def __init__(self, module_name) -> None: | ||
| 6 | self.module_name = module_name | 6 | self.module_name = module_name | ||
| 7 | 7 | ||||
| 8 | @staticmethod | 8 | @staticmethod | ||
| 9 | def __check_for_attributes(obj) -> bool: | 9 | def __check_for_attributes(obj) -> bool: | ||
| 10 | for arg in obj.__dir__(): | 10 | for arg in obj.__dir__(): | ||
| 11 | if (not re.match(r"[aeiou]{4,}", arg) and | 11 | if (not re.match(r"[aeiou]{4,}", arg) and | ||
| 12 | not re.match(r"^__.+__$", arg) and | 12 | not re.match(r"^__.+__$", arg) and | ||
| 13 | list(filter(lambda x: x.isalpha(), list(arg)))[-1].isupper()): | 13 | list(filter(lambda x: x.isalpha(), list(arg)))[-1].isupper()): | ||
| 14 | return True | 14 | return True | ||
| 15 | return False | 15 | return False | ||
| 16 | 16 | ||||
| 17 | @staticmethod | 17 | @staticmethod | ||
| 18 | def __check_for_name(obj) -> bool: | 18 | def __check_for_name(obj) -> bool: | ||
| 19 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | 19 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | ||
| 20 | 20 | ||||
| 21 | @staticmethod | 21 | @staticmethod | ||
| 22 | def __check_for_quest(obj) -> bool: | 22 | def __check_for_quest(obj) -> bool: | ||
| 23 | 23 | ||||
| 24 | def convert_doctype_to_type(doctype: str) -> object: | 24 | def convert_doctype_to_type(doctype: str) -> object: | ||
| 25 | help_values = { | 25 | help_values = { | ||
| 26 | "int": 1, | 26 | "int": 1, | ||
| 27 | "float": 1.2, | 27 | "float": 1.2, | ||
| 28 | "str": "'string'", | 28 | "str": "'string'", | ||
| 29 | "bool": True, | 29 | "bool": True, | ||
| 30 | } | 30 | } | ||
| 31 | 31 | ||||
| 32 | if not doctype.startswith('dict'): | 32 | if not doctype.startswith('dict'): | ||
| 33 | doctype = doctype.replace("[", "((") | 33 | doctype = doctype.replace("[", "((") | ||
| 34 | doctype = doctype.replace("]", ",))") | 34 | doctype = doctype.replace("]", ",))") | ||
| 35 | else: | 35 | else: | ||
| 36 | doctype = doctype.replace("[", "([(") | 36 | doctype = doctype.replace("[", "([(") | ||
| 37 | doctype = doctype.replace("]", ")])") | 37 | doctype = doctype.replace("]", ")])") | ||
| 38 | for type, value in help_values.items(): | 38 | for type, value in help_values.items(): | ||
| 39 | doctype = doctype.replace(type, str(value)) | 39 | doctype = doctype.replace(type, str(value)) | ||
| 40 | 40 | ||||
| 41 | return eval(doctype) | 41 | return eval(doctype) | ||
| 42 | 42 | ||||
| 43 | if "__call__" in dir(obj): | 43 | if "__call__" in dir(obj): | ||
| 44 | doc_string = obj.__doc__ | 44 | doc_string = obj.__doc__ | ||
| 45 | if inspect.isfunction(obj): | 45 | if inspect.isfunction(obj): | ||
| 46 | func_args = obj.__code__.co_varnames | 46 | func_args = obj.__code__.co_varnames | ||
| 47 | else: | 47 | else: | ||
| 48 | func_args = obj.__init__.__code__.co_varnames | 48 | func_args = obj.__init__.__code__.co_varnames | ||
| 49 | else: | 49 | else: | ||
| 50 | return False | 50 | return False | ||
| 51 | 51 | ||||
| 52 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | 52 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) | ||
| 53 | test_params = [[]] | 53 | test_params = [[]] | ||
| 54 | if doc_args: | 54 | if doc_args: | ||
| 55 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | 55 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | ||
| 56 | kvp = arg.split(" : ") | 56 | kvp = arg.split(" : ") | ||
| 57 | name, types = kvp | 57 | name, types = kvp | ||
| 58 | if name not in func_args: | 58 | if name not in func_args: | ||
| 59 | return False | 59 | return False | ||
| 60 | types = types.split(" | ") | 60 | types = types.split(" | ") | ||
| 61 | test_params *= len(types) | 61 | test_params *= len(types) | ||
| 62 | for i, type in enumerate(types): | 62 | for i, type in enumerate(types): | ||
| 63 | test_params[i].append(convert_doctype_to_type(type)) | 63 | test_params[i].append(convert_doctype_to_type(type)) | ||
| 64 | elif not func_args: | 64 | elif not func_args: | ||
| 65 | return True | 65 | return True | ||
| 66 | 66 | ||||
| 67 | try: | 67 | try: | ||
| n | 68 | for param in test_params: | n | 68 | for params in test_params: |
| 69 | obj(*param) | 69 | obj(*params) | ||
| 70 | except TypeError: | 70 | except: | ||
| 71 | return False | 71 | return False | ||
| 72 | 72 | ||||
| 73 | return True | 73 | return True | ||
| 74 | 74 | ||||
| 75 | def __enter__(self): | 75 | def __enter__(self): | ||
| 76 | module = __import__(self.module_name) | 76 | module = __import__(self.module_name) | ||
| 77 | for obj_name in module.__dir__(): | 77 | for obj_name in module.__dir__(): | ||
| 78 | obj = getattr(module, obj_name) | 78 | obj = getattr(module, obj_name) | ||
| t | 79 | if not self.__check_for_name(obj) or not self.__check_for_attributes(obj) or not self.__check_for_quest(obj): | t | 79 | if (not self.__check_for_name(obj) or |
| 80 | not self.__check_for_attributes(obj) or | ||||
| 81 | not self.__check_for_quest(obj)): | ||||
| 80 | delattr(module, obj_name) | 82 | delattr(module, obj_name) | ||
| 81 | return module | 83 | return module | ||
| 82 | 84 | ||||
| 83 | def __exit__(self, exc_type, exc, tb): | 85 | def __exit__(self, exc_type, exc, tb): | ||
| 84 | pass | 86 | pass | ||
| 85 | 87 | ||||
| 86 | 88 | ||||
| 87 | if __name__ == "__main__": | 89 | if __name__ == "__main__": | ||
| 88 | with BridgeKeeper("tests") as filtered_module: | 90 | with BridgeKeeper("tests") as filtered_module: | ||
| 89 | filtered_module.baba(5, 'banichka') | 91 | filtered_module.baba(5, 'banichka') | ||
| 90 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | 92 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | ||
| 91 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | 93 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | ||
| 92 | pass | 94 | pass |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | import inspect | 2 | import inspect | ||
| 3 | 3 | ||||
| 4 | class BridgeKeeper: | 4 | class BridgeKeeper: | ||
| 5 | def __init__(self, module_name) -> None: | 5 | def __init__(self, module_name) -> None: | ||
| 6 | self.module_name = module_name | 6 | self.module_name = module_name | ||
| 7 | 7 | ||||
| 8 | @staticmethod | 8 | @staticmethod | ||
| 9 | def __check_for_attributes(obj) -> bool: | 9 | def __check_for_attributes(obj) -> bool: | ||
| 10 | for arg in obj.__dir__(): | 10 | for arg in obj.__dir__(): | ||
| n | 11 | if not re.match(r"[aeiou]{4,}", arg) and not re.match(r"^__.+__$", arg) and list(filter(lambda x: x.isalpha(), list(arg)))[-1].isupper(): | n | 11 | if (not re.match(r"[aeiou]{4,}", arg) and |
| 12 | not re.match(r"^__.+__$", arg) and | ||||
| 13 | list(filter(lambda x: x.isalpha(), list(arg)))[-1].isupper()): | ||||
| 12 | return True | 14 | return True | ||
| 13 | return False | 15 | return False | ||
| 14 | 16 | ||||
| 15 | @staticmethod | 17 | @staticmethod | ||
| 16 | def __check_for_name(obj) -> bool: | 18 | def __check_for_name(obj) -> bool: | ||
| 17 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | 19 | return "__name__" in obj.__dir__() and obj.__name__[0].isupper() | ||
| 18 | 20 | ||||
| 19 | @staticmethod | 21 | @staticmethod | ||
| 20 | def __check_for_quest(obj) -> bool: | 22 | def __check_for_quest(obj) -> bool: | ||
| 21 | 23 | ||||
| 22 | def convert_doctype_to_type(doctype: str) -> object: | 24 | def convert_doctype_to_type(doctype: str) -> object: | ||
| 23 | help_values = { | 25 | help_values = { | ||
| 24 | "int": 1, | 26 | "int": 1, | ||
| 25 | "float": 1.2, | 27 | "float": 1.2, | ||
| 26 | "str": "'string'", | 28 | "str": "'string'", | ||
| 27 | "bool": True, | 29 | "bool": True, | ||
| 28 | } | 30 | } | ||
| 29 | 31 | ||||
| 30 | if not doctype.startswith('dict'): | 32 | if not doctype.startswith('dict'): | ||
| 31 | doctype = doctype.replace("[", "((") | 33 | doctype = doctype.replace("[", "((") | ||
| 32 | doctype = doctype.replace("]", ",))") | 34 | doctype = doctype.replace("]", ",))") | ||
| 33 | else: | 35 | else: | ||
| 34 | doctype = doctype.replace("[", "([(") | 36 | doctype = doctype.replace("[", "([(") | ||
| 35 | doctype = doctype.replace("]", ")])") | 37 | doctype = doctype.replace("]", ")])") | ||
| 36 | for type, value in help_values.items(): | 38 | for type, value in help_values.items(): | ||
| 37 | doctype = doctype.replace(type, str(value)) | 39 | doctype = doctype.replace(type, str(value)) | ||
| 38 | 40 | ||||
| 39 | return eval(doctype) | 41 | return eval(doctype) | ||
| 40 | 42 | ||||
| 41 | if "__call__" in dir(obj): | 43 | if "__call__" in dir(obj): | ||
| 42 | doc_string = obj.__doc__ | 44 | doc_string = obj.__doc__ | ||
| 43 | if inspect.isfunction(obj): | 45 | if inspect.isfunction(obj): | ||
| 44 | func_args = obj.__code__.co_varnames | 46 | func_args = obj.__code__.co_varnames | ||
| 45 | else: | 47 | else: | ||
| 46 | func_args = obj.__init__.__code__.co_varnames | 48 | func_args = obj.__init__.__code__.co_varnames | ||
| 47 | else: | 49 | else: | ||
| 48 | return False | 50 | return False | ||
| 49 | 51 | ||||
| n | 50 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|$)", doc_string, re.S) | n | 52 | doc_args = re.search(r"(?<=Parameters\n----------\n).+(?=\n\n|\n$|$)", doc_string, re.S) |
| 51 | test_params = [[]] | 53 | test_params = [[]] | ||
| 52 | if doc_args: | 54 | if doc_args: | ||
| 53 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | 55 | for arg in filter(lambda x: " : " in x, doc_args.group().split("\n")): | ||
| 54 | kvp = arg.split(" : ") | 56 | kvp = arg.split(" : ") | ||
| 55 | name, types = kvp | 57 | name, types = kvp | ||
| 56 | if name not in func_args: | 58 | if name not in func_args: | ||
| 57 | return False | 59 | return False | ||
| 58 | types = types.split(" | ") | 60 | types = types.split(" | ") | ||
| 59 | test_params *= len(types) | 61 | test_params *= len(types) | ||
| 60 | for i, type in enumerate(types): | 62 | for i, type in enumerate(types): | ||
| 61 | test_params[i].append(convert_doctype_to_type(type)) | 63 | test_params[i].append(convert_doctype_to_type(type)) | ||
| 62 | elif not func_args: | 64 | elif not func_args: | ||
| 63 | return True | 65 | return True | ||
| 64 | 66 | ||||
| 65 | try: | 67 | try: | ||
| 66 | for param in test_params: | 68 | for param in test_params: | ||
| 67 | obj(*param) | 69 | obj(*param) | ||
| t | 68 | except : | t | 70 | except TypeError: |
| 69 | return False | 71 | return False | ||
| 70 | 72 | ||||
| 71 | return True | 73 | return True | ||
| 72 | 74 | ||||
| 73 | def __enter__(self): | 75 | def __enter__(self): | ||
| 74 | module = __import__(self.module_name) | 76 | module = __import__(self.module_name) | ||
| 75 | for obj_name in module.__dir__(): | 77 | for obj_name in module.__dir__(): | ||
| 76 | obj = getattr(module, obj_name) | 78 | obj = getattr(module, obj_name) | ||
| 77 | if not self.__check_for_name(obj) or not self.__check_for_attributes(obj) or not self.__check_for_quest(obj): | 79 | if not self.__check_for_name(obj) or not self.__check_for_attributes(obj) or not self.__check_for_quest(obj): | ||
| 78 | delattr(module, obj_name) | 80 | delattr(module, obj_name) | ||
| 79 | return module | 81 | return module | ||
| 80 | 82 | ||||
| 81 | def __exit__(self, exc_type, exc, tb): | 83 | def __exit__(self, exc_type, exc, tb): | ||
| 82 | pass | 84 | pass | ||
| 83 | 85 | ||||
| 84 | 86 | ||||
| 85 | if __name__ == "__main__": | 87 | if __name__ == "__main__": | ||
| 86 | with BridgeKeeper("tests") as filtered_module: | 88 | with BridgeKeeper("tests") as filtered_module: | ||
| 87 | filtered_module.baba(5, 'banichka') | 89 | filtered_module.baba(5, 'banichka') | ||
| 88 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | 90 | # filtered_module.dyado # Хвърля се AttributeError, защото dyado не отговаря на въпроси 1 и 3 | ||
| 89 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | 91 | filtered_module.strinka # Хвърля се AttributeError, защото strinka не може да бъде извикана успешно с аргументите, описани в docstring-а | ||
| 90 | pass | 92 | pass |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||