def test_several_catchall_handlers(): def catchall0(node): yield ("0", node) def catchall1(node): yield ("1", node) with pytest.raises(TypeError): create_handler(catchall0, catchall1)
def test_catchall_handler_not_alone(): @xml_handle_element("a") def handle(node): yield ("0", node) def catchall(node): yield ("1", node) with pytest.raises(TypeError): create_handler(handle, catchall)
def test_class_with_handler_static_method_generator(): @xml_handle_element("x") class Handler: @xml_handle_element("a") @staticmethod def handle0(node): yield ("0", node) @xml_handle_element("b") @staticmethod def handle1(node): yield ("1", node) @staticmethod def xml_handler(generator): yield ("start", None) for txt, node in generator: yield (f"h{txt}", node) yield ("end", None) # pylint: disable=unbalanced-tuple-unpacking node_x, node_a = create_nodes("x", "a") _, node_b = create_nodes("b", parent=node_x) # pylint: enable=unbalanced-tuple-unpacking handler = create_handler(Handler) assert list(handler(node_x)) == [ ("start", None), ("h0", node_a), ("h1", node_b), ("end", None), ]
def test_class_with_handler(): @xml_handle_element("x") class Handler: def __init__(self): self.nodes = [] @xml_handle_element("a") def handle0(self, node): self.nodes.append(("x", node)) @xml_handle_element("b") def handle1(self, node): self.nodes.append(("y", node)) def xml_handler(self): yield ("start", None) for txt, node in self.nodes: yield (f"_{txt}", node) yield ("end", None) # pylint: disable=unbalanced-tuple-unpacking node_x, node_a = create_nodes("x", "a") _, node_b = create_nodes("b", parent=node_x) # pylint: enable=unbalanced-tuple-unpacking handler = create_handler(Handler) assert list(handler(node_x)) == [ ("start", None), ("_x", node_a), ("_y", node_b), ("end", None), ]
def test_class_extends_builtin_str_without_init(): @xml_handle_element("x") class Handler(str): pass nodes = create_nodes("x", "a") handler = create_handler(Handler) assert list(handler(nodes[0])) == [""]
def test_create_handler(root, expected_text, expected_node, *handles): handler = create_handler(*handles) out = list(handler(root)) if expected_node is None: assert not out elif expected_text is None: assert out == [expected_node] else: assert out == [(expected_text, expected_node)]
def test_class_without_sub_handler(): @xml_handle_element("x") class Handler: pass nodes = create_nodes("x", "y") handler = create_handler(Handler) items = list(handler(nodes[0])) assert len(items) == 1 assert isinstance(items[0], Handler)
def test_class_extends_builtin_list_without_init(): @xml_handle_element("x") class Handler(list): @xml_handle_element("a") def handle0(self, node): self.append(node) nodes = create_nodes("x", "a") handler = create_handler(Handler) assert list(handler(nodes[0])) == [[nodes[1]]]
def test_class_init_crash(): @xml_handle_element("x") class Handler: def __init__(self): raise TypeError("Something went wrong") nodes = create_nodes("x", "a") handler = create_handler(Handler) with pytest.raises(TypeError) as excinfo: list(handler(nodes[0])) assert str(excinfo.value) == "Something went wrong"
def test_class_no_handler_warning(): @xml_handle_element("x") class Handler: @xml_handle_element("a") @staticmethod def handle0(node): yield ("0", node) # this creates a warning nodes = create_nodes("x", "a") handler = create_handler(Handler) with pytest.warns(RuntimeWarning): items = list(handler(nodes[0])) assert len(items) == 1 assert isinstance(items[0], Handler)
def test_dataclass_init_two_mandatory_parameters(): @xml_handle_element("x") @dataclass class Handler: node: XMLElement answer: int nodes = create_nodes("x", "a") handler = create_handler(Handler) with pytest.raises(TypeError) as excinfo: list(handler(nodes[0])) assert "__init__ should have" in str(excinfo.value) assert "node, answer" in str(excinfo.value) assert "Add a default value for dataclass fields" in str(excinfo.value)
def test_class_init_two_mandatory_parameters(): @xml_handle_element("x") class Handler: def __init__(self, node, answer): self.node = node self.answer = answer nodes = create_nodes("x", "a") handler = create_handler(Handler) with pytest.raises(TypeError) as excinfo: list(handler(nodes[0])) assert "__init__ should have" in str(excinfo.value) assert "node, answer" in str(excinfo.value) assert "Add a default value for dataclass fields" not in str(excinfo.value)
def test_class_with_handler_static_method(): @xml_handle_element("x") class Handler: @xml_handle_element("a") @staticmethod def handle0(node): yield ("0", node) # this creates a warning @staticmethod def xml_handler(): yield ("end", None) nodes = create_nodes("x", "a") handler = create_handler(Handler) with pytest.warns(RuntimeWarning): assert list(handler(nodes[0])) == [("end", None)]
def test_class_with_handler_generator(): @xml_handle_element("x") class Handler: def __init__(self): self.nodes = [] @xml_handle_element("a") def handle0(self, node): self.nodes.append(("x", node)) yield ("0", node) @xml_handle_element("b") def handle1(self, node): self.nodes.append(("y", node)) yield ("1", node) def xml_handler(self, generator): yield ("start", None) for txt, node in self.nodes: # before consuming the generator, self.nodes is empty # the following line is never run yield (f"oops{txt}", node) for txt, node in generator: yield (f"h{txt}", node) for txt, node in self.nodes: yield (f"_{txt}", node) yield ("end", None) # pylint: disable=unbalanced-tuple-unpacking node_x, node_a = create_nodes("x", "a") _, node_b = create_nodes("b", parent=node_x) # pylint: enable=unbalanced-tuple-unpacking handler = create_handler(Handler) assert list(handler(node_x)) == [ ("start", None), ("h0", node_a), ("h1", node_b), ("_x", node_a), ("_y", node_b), ("end", None), ]
def test_class_with_handler_too_many_mandatory_params(): @xml_handle_element("x") class Handler: @xml_handle_element("a") @staticmethod def handle0(node): yield ("0", node) @staticmethod def xml_handler(generator, extra): for item in generator: yield (extra, item) nodes = create_nodes("x", "a") handler = create_handler(Handler) with pytest.raises(TypeError) as excinfo: list(handler(nodes[0])) assert "xml_handler should have" in str(excinfo.value) assert "generator, extra" in str(excinfo.value)
def test_class_init(init_mandatory, init_optional): if init_mandatory: if init_optional: @xml_handle_element("x", "y") class Handler: def __init__(self, node, answer=42): self.seen = [] self.root = node self.answer = answer @xml_handle_element("a", "b") def handle0(self, node): self.seen.append(node) else: @xml_handle_element("x", "y") class Handler: def __init__(self, node): self.seen = [] self.root = node @xml_handle_element("a", "b") def handle0(self, node): self.seen.append(node) else: if init_optional: @xml_handle_element("x", "y") class Handler: def __init__(self, answer=42): self.seen = [] self.answer = answer @xml_handle_element("a", "b") def handle0(self, node): self.seen.append(node) else: @xml_handle_element("x", "y") class Handler: def __init__(self): self.seen = [] @xml_handle_element("a", "b") def handle0(self, node): self.seen.append(node) # x -> y0 -> a0 -> b0 # -> b1 # -> a1 -> b2 # -> y1 -> a2 -> b3 # # Handler should be instanciated on y0 and y1 # # the use of namespaces below is to avoid e.g. node_y0==node_y1 # # pylint: disable=unbalanced-tuple-unpacking node_x, node_y0 = create_nodes("x", "{y0}y") _, node_a0, node_b0 = create_nodes("{a0}a", "{b0}b", parent=node_y0) _, node_b1 = create_nodes("{b1}b", parent=node_a0) _, _, node_b2 = create_nodes("{a1}a", "{b2}b", parent=node_y0) _, node_y1, _, node_b3 = create_nodes("{n1}y", "{a2}a", "{b3}b", parent=node_x) # pylint: enable=unbalanced-tuple-unpacking handler = create_handler(Handler) items = list(handler(node_x)) assert all(isinstance(item, Handler) for item in items) assert len(items) == 2 assert items[0].seen == [node_b0, node_b1, node_b2] assert items[1].seen == [node_b3] if init_mandatory: assert items[0].root == node_y0 assert items[1].root == node_y1 if init_optional: assert items[0].answer == 42 assert items[1].answer == 42
def test_invalid_handler_type(handler): with pytest.raises(TypeError): create_handler(handler)
def test_no_handlers(): handler = create_handler() node = Mock() assert not list(handler(node))
def iter_from(self, *handlers): if not self._handle: raise RuntimeError("No handle to use") handler = create_handler(*handlers) return self._handle(handler) # pylint: disable=not-callable