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

angelolab / tmi / 198

pending completion
198

Pull #18

travis-ci-com

web-flow
Merge b7d4d1006 into 6b5a3665d
Pull Request #18: Loosened Pillow Dependencies

246 of 257 branches covered (95.72%)

Branch coverage included in aggregate %.

430 of 442 relevant lines covered (97.29%)

0.97 hits per line

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

94.23
/src/tmi/misc_utils.py
1
import os
1✔
2
import warnings
1✔
3
from collections.abc import Iterable
1✔
4
from typing import Any
1✔
5

6
import matplotlib.pyplot as plt
1✔
7
import numpy as np
1✔
8
import xarray as xr
1✔
9

10
from tmi import io_utils
1✔
11

12

13
def save_figure(save_dir, save_file, dpi=None):
1✔
14
    """Verify save_dir and save_file, then save to specified location
15

16
    Args:
17
        save_dir (str):
18
            the name of the directory we wish to save to
19
        save_file (str):
20
            the name of the file we wish to save to
21
        dpi (float):
22
            the resolution of the figure
23
    """
24

25
    # path validation
26
    io_utils.validate_paths(save_dir)
×
27

28
    # verify that if save_dir specified, save_file must also be specified
29
    if save_file is None:
×
30
        raise FileNotFoundError("save_dir specified but no save_file specified")
×
31

32
    plt.savefig(os.path.join(save_dir, save_file), dpi=dpi)
×
33

34

35
def create_invalid_data_str(invalid_data):
1✔
36
    """Creates a easy to read string for ValueError statements.
37

38
    Args:
39
        invalid_data (list[str]): A list of strings containing the invalid / missing data
40

41
    Returns:
42
        str: Returns a formatted string for more detailed ValueError outputs.
43
    """
44
    # Holder for the error string
45
    err_str_data = ""
1✔
46

47
    # Adding up to 10 invalid values to the err_str_data.
48
    for idx, data in enumerate(invalid_data[:10], start=1):
1✔
49
        err_msg = "{idx:{fill}{align}{width}} {message}\n".format(
1✔
50
            idx=idx,
51
            message=data,
52
            fill=" ",
53
            align="<",
54
            width=12,
55
        )
56
        err_str_data += err_msg
1✔
57

58
    return err_str_data
1✔
59

60

61
def make_iterable(a: Any, ignore_str: bool = True):
1✔
62
    """Convert noniterable type to singleton in list
63

64
    Args:
65
        a (T | Iterable[T]):
66
            value or iterable of type T
67
        ignore_str (bool):
68
            whether to ignore the iterability of the str type
69

70
    Returns:
71
        List[T]:
72
            a as singleton in list, or a if a was already iterable.
73
    """
74
    return (
1✔
75
        a
76
        if isinstance(a, Iterable)
77
        and not ((isinstance(a, str) and ignore_str) or isinstance(a, type))
78
        else [a]
79
    )
80

81

82
def verify_in_list(warn=False, **kwargs):
1✔
83
    """Verify at least whether the values in the first list exist in the second
84

85
    Args:
86
        warn (bool):
87
            Whether to issue warning instead of error, defaults to False
88
        **kwargs (list, list):
89
            Two lists, but will work for single elements as well.
90
            The first list specified will be tested to see
91
            if all its elements are contained in the second.
92

93
    Raises:
94
        ValueError:
95
            if not all values in the first list are found in the second
96
        Warning:
97
            if not all values are found and warn is True
98
    """
99

100
    if len(kwargs) != 2:
1✔
101
        raise ValueError("You must provide 2 arguments to verify_in_list")
1✔
102

103
    test_list, good_values = kwargs.values()
1✔
104
    test_list = list(make_iterable(test_list))
1✔
105
    good_values = list(make_iterable(good_values))
1✔
106

107
    for v in [test_list, good_values]:
1✔
108
        if len(v) == 0:
1✔
109
            raise ValueError("List arguments cannot be empty")
1✔
110

111
    if not np.isin(test_list, good_values).all():
1✔
112
        test_list_name, good_values_name = kwargs.keys()
1✔
113
        test_list_name = test_list_name.replace("_", " ")
1✔
114
        good_values_name = good_values_name.replace("_", " ")
1✔
115

116
        # Calculate the difference between the `test_list` and the `good_values`
117
        difference = [str(val) for val in test_list if val not in good_values]
1✔
118

119
        # Only printing up to the first 10 invalid values.
120
        err_str = (
1✔
121
            "Not all values given in list {0:^} were found in list {1:^}.\n "
122
            "Displaying {2} of {3} invalid value(s) for list {4:^}\n"
123
        ).format(
124
            test_list_name,
125
            good_values_name,
126
            min(len(difference), 10),
127
            len(difference),
128
            test_list_name,
129
        )
130

131
        err_str += create_invalid_data_str(difference)
1✔
132

133
        if warn:
1✔
134
            warnings.warn(err_str)
1✔
135
        else:
136
            raise ValueError(err_str)
1✔
137

138

139
def verify_same_elements(enforce_order=False, warn=False, **kwargs):
1✔
140
    """Verify if two lists contain the same elements regardless of count
141

142
    Args:
143
        enforce_order (bool):
144
            Whether to also check for the same ordering between the two lists
145
        warn (bool):
146
            Whether to issue warning instead of error, defaults to False
147
        **kwargs (list, list):
148
            Two lists
149

150
    Raises:
151
        ValueError:
152
            if the two lists don't contain the same elements
153
    """
154

155
    if len(kwargs) != 2:
1✔
156
        raise ValueError("You must provide 2 list arguments to verify_same_elements")
1✔
157

158
    list_one, list_two = kwargs.values()
1✔
159

160
    try:
1✔
161
        list_one_cast = list(list_one)
1✔
162
        list_two_cast = list(list_two)
1✔
163
    except TypeError:
1✔
164
        raise ValueError("Both arguments provided must be lists or list types")
1✔
165

166
    list_one_name, list_two_name = kwargs.keys()
1✔
167
    list_one_name = list_one_name.replace("_", " ")
1✔
168
    list_two_name = list_two_name.replace("_", " ")
1✔
169

170
    if not np.all(set(list_one_cast) == set(list_two_cast)):
1✔
171
        # Values in list one that are not in list two
172
        missing_vals_1 = [str(val) for val in (set(list_one_cast) - set(list_two_cast))]
1✔
173

174
        # Values in list two that are not in list one
175
        missing_vals_2 = [str(val) for val in (set(list_two_cast) - set(list_one_cast))]
1✔
176

177
        # Total missing values
178
        missing_vals_total = [str(val) for val in set(list_one_cast) ^ set(list_two_cast)]
1✔
179

180
        err_str = (
1✔
181
            "{0} value(s) provided for list {1:^} and list {2:^} are not found in both lists.\n"
182
        ).format(len(missing_vals_total), list_one_name, list_two_name)
183

184
        # Only printing up to the first 10 invalid values for list one.
185
        err_str += ("{0:>13} \n").format(
1✔
186
            "Displaying {0} of {1} value(s) in list {2} that are missing from list {3}\n".format(
187
                min(len(missing_vals_1), 10), len(missing_vals_1), list_one_name, list_two_name
188
            )
189
        )
190
        err_str += create_invalid_data_str(missing_vals_1) + "\n"
1✔
191

192
        # Only printing up to the first 10 invalid values for list two
193
        err_str += ("{0:>13} \n").format(
1✔
194
            "Displaying {0} of {1} value(s) in list {2} that are missing from list {3}\n".format(
195
                min(len(missing_vals_2), 10), len(missing_vals_2), list_two_name, list_one_name
196
            )
197
        )
198
        err_str += create_invalid_data_str(missing_vals_2) + "\n"
1✔
199

200
        if warn:
1✔
201
            warnings.warn(err_str)
1✔
202
        else:
203
            raise ValueError(err_str)
1✔
204
    elif enforce_order and list_one_cast != list_two_cast:
1✔
205
        first_bad_index = next(
1!
206
            i for i, (l1, l2) in enumerate(zip(list_one_cast, list_two_cast)) if l1 != l2
207
        )
208

209
        err_str = "Lists %s and %s ordered differently: values %s and %s do not match at index %d"
1✔
210

211
        if warn:
1✔
212
            warnings.warn(
1✔
213
                err_str
214
                % (
215
                    list_one_name,
216
                    list_two_name,
217
                    list_one_cast[first_bad_index],
218
                    list_two_cast[first_bad_index],
219
                    first_bad_index,
220
                )
221
            )
222
        else:
223
            raise ValueError(
1✔
224
                err_str
225
                % (
226
                    list_one_name,
227
                    list_two_name,
228
                    list_one_cast[first_bad_index],
229
                    list_two_cast[first_bad_index],
230
                    first_bad_index,
231
                )
232
            )
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

© 2025 Coveralls, Inc