• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

deepset-ai / canals / 5904360556

18 Aug 2023 03:25PM UTC coverage: 92.818% (-0.5%) from 93.304%
5904360556

push

github

web-flow
Change @component decorator so it doesn't add default to_dict and from_dict (#98)

179 of 184 branches covered (97.28%)

Branch coverage included in aggregate %.

661 of 721 relevant lines covered (91.68%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
canals/testing/factory.py
1
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
2
#
3
# SPDX-License-Identifier: Apache-2.0
4
from typing import Any, Dict, Optional, Tuple, Type
1✔
5

6
from canals import component, Component
1✔
7
from canals.serialization import default_to_dict, default_from_dict
1✔
8

9

10
def component_class(
1✔
11
    name: str,
12
    input_types: Optional[Dict[str, Any]] = None,
13
    output_types: Optional[Dict[str, Any]] = None,
14
    output: Optional[Dict[str, Any]] = None,
15
    bases: Optional[Tuple[type, ...]] = None,
16
    extra_fields: Optional[Dict[str, Any]] = None,
17
) -> Type[Component]:
18
    """
19
    Utility class to create a Component class with the given name and input and output types.
20

21
    If `output` is set but `output_types` is not, `output_types` will be set to the types of the values in `output`.
22
    Though if `output_types` is set but `output` is not the component's `run` method will return a dictionary
23
    of the same keys as `output_types` all with a value of None.
24

25
    ### Usage
26

27
    Create a component class with default input and output types:
28
    ```python
29
    MyFakeComponent = component_class_factory("MyFakeComponent")
30
    component = MyFakeComponent()
31
    output = component.run(value=1)
32
    assert output == {"value": None}
33
    ```
34

35
    Create a component class with an "value" input of type `int` and with a "value" output of `10`:
36
    ```python
37
    MyFakeComponent = component_class_factory(
38
        "MyFakeComponent",
39
        input_types={"value": int},
40
        output={"value": 10}
41
    )
42
    component = MyFakeComponent()
43
    output = component.run(value=1)
44
    assert output == {"value": 10}
45
    ```
46

47
    Create a component class with a custom base class:
48
    ```python
49
    MyFakeComponent = component_class_factory(
50
        "MyFakeComponent",
51
        bases=(MyBaseClass,)
52
    )
53
    component = MyFakeComponent()
54
    assert isinstance(component, MyBaseClass)
55
    ```
56

57
    Create a component class with an extra field `my_field`:
58
    ```python
59
    MyFakeComponent = component_class_factory(
60
        "MyFakeComponent",
61
        extra_fields={"my_field": 10}
62
    )
63
    component = MyFakeComponent()
64
    assert component.my_field == 10
65
    ```
66

67
    Args:
68
    name: Name of the component class
69
    input_types: Dictionary of string and type that defines the inputs of the component,
70
        if set to None created component will expect a single input "value" of Any type.
71
        Defaults to None.
72
    output_types: Dictionary of string and type that defines the outputs of the component,
73
        if set to None created component will return a single output "value" of NoneType and None value.
74
        Defaults to None.
75
    output: Actual output dictionary returned by the created component run,
76
        is set to None it will return a dictionary of string and None values.
77
        Keys will be the same as the keys of output_types. Defaults to None.
78
    bases: Base classes for this component, if set to None only base is object. Defaults to None.
79
    extra_fields: Extra fields for the Component, defaults to None.
80

81
    :return: A class definition that can be used as a component.
82
    """
83
    if input_types is None:
1✔
84
        input_types = {"value": Any}
1✔
85
    if output_types is None and output is not None:
1✔
86
        output_types = {key: type(value) for key, value in output.items()}
1✔
87
    elif output_types is None:
1✔
88
        output_types = {"value": type(None)}
1✔
89

90
    def init(self):
1✔
91
        component.set_input_types(self, **input_types)
1✔
92
        component.set_output_types(self, **output_types)
1✔
93

94
    # Both arguments are necessary to correctly define
95
    # run but pylint doesn't like that we don't use them.
96
    # It's fine ignoring the warning here.
97
    def run(self, **kwargs):  # pylint: disable=unused-argument
1✔
98
        if output is not None:
1✔
99
            return output
1✔
100
        return {name: None for name in output_types.keys()}
1✔
101

102
    def to_dict(self):
1✔
103
        return default_to_dict(self)
×
104

105
    def from_dict(cls, data: Dict[str, Any]):
1✔
106
        return default_from_dict(cls, data)
×
107

108
    fields = {
1✔
109
        "__init__": init,
110
        "run": run,
111
        "to_dict": to_dict,
112
        "from_dict": classmethod(from_dict),
113
    }
114
    if extra_fields is not None:
1✔
115
        fields = {**fields, **extra_fields}
1✔
116

117
    if bases is None:
1✔
118
        bases = (object,)
1✔
119

120
    cls = type(name, bases, fields)
1✔
121
    return component(cls)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc