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

deepset-ai / haystack / 15067549553

16 May 2025 11:36AM UTC coverage: 90.475% (+0.03%) from 90.445%
15067549553

Pull #9345

github

web-flow
Merge 0c4204fda into 707573d96
Pull Request #9345: feat: add serialization to `State` / move `State` to utils

11000 of 12158 relevant lines covered (90.48%)

0.9 hits per line

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

95.45
haystack/utils/base_serialization.py
1
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
2
#
3
# SPDX-License-Identifier: Apache-2.0
4

5
from typing import Any, Dict
1✔
6

7
from haystack.core.errors import DeserializationError, SerializationError
1✔
8
from haystack.core.serialization import generate_qualified_class_name, import_class_by_name
1✔
9

10

11
def serialize_class_instance(obj: Any) -> Dict[str, Any]:
1✔
12
    """
13
    Serializes an object that has a `to_dict` method into a dictionary.
14

15
    :param obj:
16
        The object to be serialized.
17
    :returns:
18
        A dictionary representation of the object.
19
    :raises SerializationError:
20
        If the object does not have a `to_dict` method.
21
    """
22
    if not hasattr(obj, "to_dict"):
1✔
23
        raise SerializationError(f"Object of class '{type(obj).__name__}' does not have a 'to_dict' method")
1✔
24

25
    output = obj.to_dict()
1✔
26
    return {"type": generate_qualified_class_name(type(obj)), "data": output}
1✔
27

28

29
def deserialize_class_instance(data: Dict[str, Any]) -> Any:
1✔
30
    """
31
    Deserializes an object from a dictionary representation generated by `auto_serialize_class_instance`.
32

33
    :param data:
34
        The dictionary to deserialize from.
35
    :returns:
36
        The deserialized object.
37
    :raises DeserializationError:
38
        If the serialization data is malformed, the class type cannot be imported, or the
39
        class does not have a `from_dict` method.
40
    """
41
    if "type" not in data:
1✔
42
        raise DeserializationError("Missing 'type' in serialization data")
1✔
43
    if "data" not in data:
1✔
44
        raise DeserializationError("Missing 'data' in serialization data")
1✔
45

46
    try:
1✔
47
        obj_class = import_class_by_name(data["type"])
1✔
48
    except ImportError as e:
1✔
49
        raise DeserializationError(f"Class '{data['type']}' not correctly imported") from e
1✔
50

51
    if not hasattr(obj_class, "from_dict"):
1✔
52
        raise DeserializationError(f"Class '{data['type']}' does not have a 'from_dict' method")
1✔
53

54
    return obj_class.from_dict(data["data"])
1✔
55

56

57
def serialize_value(value: Any) -> Any:
1✔
58
    """
59
    Serializes a value into a format suitable for storage or transmission.
60

61
    Handles various types including:
62
    - Haystack dataclass objects (Answer, Document, etc.)
63
    - Primitive types (returned as is)
64
    - Lists of primitives (returned as is)
65
    - Lists of complex types (recursively serialized)
66
    - Dictionaries (recursively serialized)
67

68
    :param value: The value to serialize
69
    :returns: The serialized representation of the value
70
    """
71

72
    if hasattr(value, "to_dict") and callable(getattr(value, "to_dict")):
1✔
73
        serialized_value = value.to_dict()
1✔
74
        serialized_value["_type"] = generate_qualified_class_name(type(value))
1✔
75

76
        return serialized_value
1✔
77

78
    # this is a hack to serialize inputs that don't have a to_dict
79
    elif hasattr(value, "__dict__"):
1✔
80
        return {"_type": value.__class__, "attributes": value.__dict__}
×
81

82
    # recursively serialize all inputs in a dict
83
    elif isinstance(value, dict):
1✔
84
        return {k: serialize_value(v) for k, v in value.items()}
1✔
85

86
    # recursively serialize all inputs in lists or tuples
87
    elif isinstance(value, (list, tuple, set)):
1✔
88
        return type(value)(serialize_value(item) for item in value)
1✔
89

90
    return value
1✔
91

92

93
# pylint: disable=too-many-return-statements
94
def deserialize_value(value: Any) -> Any:
1✔
95
    """
96
    Deserializes a value from its serialized representation.
97

98
    Handles various types including:
99
    - Haystack dataclass objects (Answer, Document, etc.)
100
    - Primitive types (returned as is)
101
    - Lists of primitives (returned as is)
102
    - Lists of complex types (recursively deserialized)
103
    - Dictionaries (recursively deserialized)
104

105
    :param value: The serialized value to deserialize
106
    :returns: The deserialized value
107
    """
108

109
    # None or primitive types are returned as is
110
    if not value or isinstance(value, (str, int, float, bool)):
1✔
111
        return value
1✔
112

113
    # check if the dictionary has a "_type" key and the class type has a "from_dict" method
114
    if isinstance(value, dict):
1✔
115
        if "_type" in value:
1✔
116
            obj_class = import_class_by_name(value.pop("_type"))
1✔
117
            if hasattr(obj_class, "from_dict"):
1✔
118
                return obj_class.from_dict(value)
1✔
119

120
        # If not a known type, recursively deserialize each item in the dictionary
121
        return {k: deserialize_value(v) for k, v in value.items()}
1✔
122

123
    if isinstance(value, (list, tuple, set)):
1✔
124
        return type(value)(deserialize_value(i) for i in value)
1✔
125

126
    return value
×
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