diff --git a/soda/core/soda/common/yaml_helper.py b/soda/core/soda/common/yaml_helper.py index 46c9a3576..3dd425c3b 100644 --- a/soda/core/soda/common/yaml_helper.py +++ b/soda/core/soda/common/yaml_helper.py @@ -1,3 +1,5 @@ +import threading + from ruamel.yaml import YAML, StringIO @@ -14,16 +16,53 @@ def to_yaml_str(yaml_object) -> str: class YamlHelper: - __yaml = create_yaml() + """ + A helper class to serialize and deserialize objects to and from YAML format. + This class is thread-safe and ensures that each thread has its own instance of the YAML parser/dumper. + + Usage: + YamlHelper.to_yaml(yaml_object) + YamlHelper.from_yaml(yaml_string) + """ + + _thread_local = threading.local() + + @classmethod + def _get_yaml(cls): + """ + Returns a thread-local YAML instance for serializing and deserializing YAML data. + If no instance exists for the current thread, a new one is created. + + :return: a YAML instance specific to the current thread. + """ + if not hasattr(cls._thread_local, "yaml"): + cls._thread_local.yaml = create_yaml() + return cls._thread_local.yaml @classmethod def to_yaml(cls, yaml_object) -> str: + """ + Serializes a Python object into a YAML formatted string. + + :param object yaml_object: The Python object to serialize. + :return: the YAML formatted string, or an empty string if the input is None. + """ if yaml_object is None: return "" - stream = StringIO() - cls.__yaml.dump(yaml_object, stream) - return stream.getvalue() + with StringIO() as stream: + yaml_instance = cls._get_yaml() + yaml_instance.dump(yaml_object, stream) + return stream.getvalue() @classmethod def from_yaml(cls, yaml_str) -> object: - return cls.__yaml.load(yaml_str) + """ + Deserializes a YAML formatted string into a Python object. + + :param str yaml_str: the YAML formatted string to deserialize. + :return: the deserialized Python object, or None if the input is None or empty. + """ + if yaml_str is None or not yaml_str.strip(): + return None + yaml_instance = cls._get_yaml() + return yaml_instance.load(yaml_str)