Skip to content

quast_decisiontree.core.utils

quast_decisiontree.core.utils

reset_data

reset_data()
Source code in src/quast_decisiontree/core/utils.py
16
17
18
19
20
def reset_data():
    path = []
    problem_data = {}
    nodes_in_path = []
    return path, problem_data, nodes_in_path

add_new_keys

add_new_keys(dict1, dict2, ignore=None)

adds all items from dict2 whose keys aren't contained in dict1

Mutates dict1 in place and returns it (not a copy).

ignore (optional, list): keys from dict2 that should not be added

Source code in src/quast_decisiontree/core/utils.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def add_new_keys(dict1: dict, dict2: dict, ignore: list | None = None) -> dict:
    """adds all items from dict2 whose keys aren't contained in dict1

    Mutates dict1 in place and returns it (not a copy).

    ignore (optional, list): keys from dict2 that should not be added
    """

    if ignore is None:
        ignore = []

    out = dict1
    for key in dict2.keys():
        if (key not in out.keys()) and (key not in ignore):
            out[key] = dict2[key]
    return out

load_file_if_not_none

load_file_if_not_none(path)

loads the dictionary at the specified path if not None, else returns an empty dictionary

Source code in src/quast_decisiontree/core/utils.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def load_file_if_not_none(path: str | None) -> dict:
    """loads the dictionary at the specified path if not None,
    else returns an empty dictionary
    """
    if path is None:
        return dict()
    elif path.endswith(".json"):
        with open(path, encoding="utf8") as file:
            return json.load(file)
    elif path.endswith(".yaml"):
        with open(path, encoding="utf8") as f:
            return yaml.load(f, Loader=yaml.FullLoader)
    else:
        raise ValueError(f"Unsupported file type in {path}. Accepted types: json, yaml")

expand_data_path

expand_data_path(config_dict, cwd=None)

if a data_folder key is contained in the dictionary, it will be expanded to a real path

Parameters:

Name Type Description Default
config_dict dict

the dictionary

required
cwd Union[str, None]

if a relative path is encountered, this will be taken

None
Source code in src/quast_decisiontree/core/utils.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def expand_data_path(config_dict: dict, cwd: str | None = None) -> None:
    """if a data_folder key is contained in the dictionary, it will be expanded to a real path

    Args:
        config_dict (dict): the dictionary
        cwd (Union[str, None], optional): if a relative path is encountered, this will be taken
        as the working directory. If None, the working directory will be set by os.getcwd().
        Defaults to None.
    """
    if "data_folder" not in config_dict:
        return

    config_dict["data_folder"] = os.path.expanduser(config_dict["data_folder"])
    if os.path.isabs(config_dict["data_folder"]):
        return

    if cwd is None:
        cwd = os.getcwd()

    config_dict["data_folder"] = os.path.normpath(os.path.join(cwd, config_dict["data_folder"]))
    return

read_config

read_config(
    config_dict=None,
    config_path=None,
    standard_config_path=None,
)

generates a config dictionary from the arguments with the priority

config_dict > file at config_path > file at standard_config_path

Source code in src/quast_decisiontree/core/utils.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def read_config(config_dict=None, config_path=None, standard_config_path=None) -> dict:
    """generates a config dictionary from the arguments with the priority

    config_dict > file at config_path > file at standard_config_path
    """
    if config_dict is None:
        out = dict()
    else:
        out = config_dict
    expand_data_path(out)

    config_path = to_abspath_if_not_none(config_path)
    try:
        out = add_new_keys(out, load_file_if_not_none(config_path))
        if config_path is not None:
            expand_data_path(out, os.path.dirname(config_path))
        else:
            expand_data_path(out)
    except FileNotFoundError:
        pass  # config file is optional

    standard_config_path = to_abspath_if_not_none(standard_config_path)
    out = add_new_keys(out, load_file_if_not_none(standard_config_path))
    if standard_config_path is not None:
        expand_data_path(out, os.path.dirname(standard_config_path))
    else:
        expand_data_path(out)

    return out

cnf_list

cnf_list(input_, dtype=str)

converts the input to a list in conjunctive-normal form with dtype specifying the base unit.

Parameters:

Name Type Description Default
input Any

the input. Can be - either a single value of type dtype - a list of values of type dtype - a list where each element is either of the two above

required

Returns:

Type Description

List[List[dtype]]: A nested list. All inputs are cast into the form [[dtype1, dtype2...], [dtype3, dtype4...]]. If the input list is [dtype1, dtype 2] the output is [[dtype1], [dtype2]], and not simply np.atleast_2d(input)

Source code in src/quast_decisiontree/core/utils.py
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
def cnf_list(input_: Any, dtype: type = str):
    """converts the input to a list in conjunctive-normal form with dtype specifying the
    base unit.

    Args:
        input (Any): the input. Can be
            - either a single value of type dtype
            - a list of values of type dtype
            - a list where each element is either of the two above

    Returns:
        List[List[dtype]]: A nested list. All inputs are cast into the form
            [[dtype1, dtype2...], [dtype3, dtype4...]]. If the input list is [dtype1, dtype 2]
            the output is [[dtype1], [dtype2]], and not simply np.atleast_2d(input)
    """
    out = []
    if isinstance(input_, list):
        for or_clause in input_:
            if isinstance(or_clause, list):
                if all(isinstance(elem, dtype) for elem in or_clause):
                    out.append(or_clause)
                else:
                    raise ValueError(f"Or clause {or_clause} contains an invalid element.")
            elif isinstance(or_clause, dtype):
                out.append([or_clause])
            else:
                raise ValueError(f"{or_clause} is neither a single {dtype} nor a list of {dtype}.")
    elif isinstance(input_, dtype):
        out.append([input_])
    else:
        raise ValueError(
            f"{input_} could not be interpreted as conjunctive normal form of {dtype} primitives."
        )
    return out

flatten_cnf

flatten_cnf(cnf_list)

flattens a list in conjunctive normal form, eliminating possible duplicate entries while doing so.

Parameters:

Name Type Description Default
cnf_list list

A list of lists, where each inner list represents an or_clause that should be combined in an AND manner in the outer layer.

required

Returns:

Name Type Description
list list

A list containing each key appearing in an or clause, in first-seen order and without duplicates.

Source code in src/quast_decisiontree/core/utils.py
147
148
149
150
151
152
153
154
155
156
157
158
159
def flatten_cnf(cnf_list: list) -> list:
    """flattens a list in conjunctive normal form, eliminating possible duplicate entries while
    doing so.

    Args:
        cnf_list (list): A list of lists, where each inner list represents an or_clause that
            should be combined in an AND manner in the outer layer.

    Returns:
        list: A list containing each key appearing in an or clause, in first-seen order and
            without duplicates.
    """
    return list(dict.fromkeys(x for or_clause in cnf_list for x in or_clause))

to_abspath_if_not_none

to_abspath_if_not_none(path)

Converts a path containing symbolic links into an abspath. If None is passed, None is returned.

Parameters:

Name Type Description Default
path Union[str, None]

the input path, or None

required

Returns:

Type Description
str | None

Union[str, None]: the output path, or None

Source code in src/quast_decisiontree/core/utils.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def to_abspath_if_not_none(path: str | None) -> str | None:
    """Converts a path containing symbolic links into an abspath. If None is passed,
    None is returned.

    Args:
        path (Union[str, None]): the input path, or None

    Returns:
        Union[str, None]: the output path, or None
    """
    if path is None:
        return None
    else:
        out = os.path.expanduser(path)
        return os.path.abspath(out)

print_dictionary

print_dictionary(dictionary, title='', key_width=20)
Source code in src/quast_decisiontree/core/utils.py
179
180
181
def print_dictionary(dictionary, title: str = "", key_width=20):
    for line in fmt_dictionary(dictionary, title, key_width):
        print(line)

fmt_dictionary

fmt_dictionary(dictionary, title='', key_width=20)
Source code in src/quast_decisiontree/core/utils.py
184
185
186
187
188
189
190
191
192
193
194
def fmt_dictionary(dictionary, title: str = "", key_width=20):
    out = []
    if len(dictionary) > 0:
        out.append(f"{title:=^50}")
        for key, val in dictionary.items():
            out.append(f"{str(key).ljust(key_width, ' ')}: {val}")
        out.append("=" * 50)
    else:
        out.append(f"{'Empty dictionary.':=^50}")

    return out

create_folder

create_folder(base_folder, folder_name)

creates a folder and returns it full path

Source code in src/quast_decisiontree/core/utils.py
197
198
199
200
201
def create_folder(base_folder, folder_name) -> str:
    """creates a folder and returns it full path"""
    folder = os.path.join(base_folder, folder_name)
    os.makedirs(folder, exist_ok=False)
    return folder