# Path: craft_ai/errors.py
# class CraftAiError(Exception):
#     """Base class for exceptions in the craft ai client."""
# 
#     def __init__(self, message=None, metadata=None):
#         self.message = message
#         self.metadata = metadata
#         super(CraftAiError, self).__init__(message, metadata)
# 
#     def __str__(self):
#         return repr(self.message)


from copy import copy
from .errors import CraftAiError
    return path0[:-1] == path1[:-1] and path0 != path1


def _get_neighbours(paths, decision_path):
    """
    Collect all neighbours paths of the given decision path
    param: paths: paths aggregator
    param: decision_path: decision path to get neighbours from
    """
    split = decision_path.split("-")
    neighbours = []
    for step in range(1, len(split) + 1):
        for path in paths:
            if _is_neighbour(path, "-".join(split[:step])):
                neighbours.append(path)
    return neighbours


def extract_output_tree(tree, output_property=None):
    """
    Extract the output decision tree specific for a given output property from a full decision tree.

    This function accepts trees as retrieved from `craft_ai.Client.get_generator_decision_tree`.

    Parameters:
        tree: A tree.
        output_property (optional): If provided, the output property for which the tree predicts
            values, otherwise the first defined tree is retrieved.
    """
    if not isinstance(tree, dict):

# Path: craft_ai/errors.py
# class CraftAiError(Exception):
#     """Base class for exceptions in the craft ai client."""
# 
#     def __init__(self, message=None, metadata=None):
#         self.message = message
#         self.metadata = metadata
#         super(CraftAiError, self).__init__(message, metadata)
# 
#     def __str__(self):
#         return repr(self.message)


# Path: craft_ai/tree_utils.py
from copy import copy
from .errors import CraftAiError

    return path0[:-1] == path1[:-1] and path0 != path1


def _get_neighbours(paths, decision_path):
    """
    Collect all neighbours paths of the given decision path
    param: paths: paths aggregator
    param: decision_path: decision path to get neighbours from
    """
    split = decision_path.split("-")
    neighbours = []
    for step in range(1, len(split) + 1):
        for path in paths:
            if _is_neighbour(path, "-".join(split[:step])):
                neighbours.append(path)
    return neighbours


def extract_output_tree(tree, output_property=None):
    """
    Extract the output decision tree specific for a given output property from a full decision tree.

    This function accepts trees as retrieved from `craft_ai.Client.get_generator_decision_tree`.

    Parameters:
        tree: A tree.
        output_property (optional): If provided, the output property for which the tree predicts
            values, otherwise the first defined tree is retrieved.
    """
    if not isinstance(tree, dict):

        raise CraftAiError(