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

pyiron / pyiron_base / 11228705564

08 Oct 2024 04:41AM UTC coverage: 71.833%. Remained the same
11228705564

push

github

web-flow
Merge pull request #1659 from pyiron/pre-commit-ci-update-config

[pre-commit.ci] pre-commit autoupdate

7480 of 10413 relevant lines covered (71.83%)

0.72 hits per line

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

19.33
/pyiron_base/utils/parser.py
1
# coding: utf-8
2
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
3
# Distributed under the terms of "New BSD License", see the LICENSE file.
4
"""
5
General purpose output parser
6
"""
7

8
import ast
1✔
9
from typing import Any, Dict, List, Optional, Tuple, Union
1✔
10

11
import numpy as np
1✔
12

13
__author__ = "Joerg Neugebauer"
1✔
14
__copyright__ = (
1✔
15
    "Copyright 2020, Max-Planck-Institut für Eisenforschung GmbH - "
16
    "Computational Materials Design (CM) Department"
17
)
18
__version__ = "1.0"
1✔
19
__maintainer__ = "Jan Janssen"
1✔
20
__email__ = "janssen@mpie.de"
1✔
21
__status__ = "production"
1✔
22
__date__ = "Sep 1, 2017"
1✔
23

24

25
def extract_data_from_str_lst(
1✔
26
    str_lst: List[str], tag: str, num_args: int = 1
27
) -> List[Union[str, List[str]]]:
28
    """
29
    General purpose routine to extract any static from a log (text) file
30

31
    Args:
32
        str_lst (List[str]): list of strings representing the lines in the file
33
        tag (str): string at the beginning of the line
34
        num_args (int): number of arguments separated by ' ' or ',' to extract after the tag
35

36
    Returns:
37
        List[Union[str, List[str]]]: List of arguments extracted as strings
38
    """
39

40
    def multiple_delimiter_split(s: str, seps: List[str]) -> List[str]:
×
41
        res = [s]
×
42
        for sep in seps:
×
43
            s, res = res, []
×
44
            for seq in s:
×
45
                res += seq.split(sep)
×
46
        while "" in res:
×
47
            res.remove("")
×
48
        return res
×
49

50
    collector = []
×
51
    ind_start = len(tag.split())
×
52
    for line_in_file in str_lst:
×
53
        if line_in_file.startswith(tag):
×
54
            collector = []
×
55
            vals = multiple_delimiter_split(line_in_file, (" ", ","))
×
56
            if num_args == 1:
×
57
                collector.append(vals[ind_start])
×
58
            else:
59
                collector.append(vals[ind_start : num_args + ind_start])
×
60

61
    return collector
×
62

63

64
def extract_data_from_file(
1✔
65
    file_name: str, tag: str, num_args: int = 1
66
) -> List[Union[str, List[str]]]:
67
    """
68
    General purpose routine to extract any static from a log (text) file
69

70
    Args:
71
        file_name (str): file name or path to the file, can either be absolute or relative
72
        tag (str): string at the beginning of the line
73
        num_args (int): number of arguments separated by ' ' or ',' to extract after the tag
74

75
    Returns:
76
        List[Union[str, List[str]]]: List of arguments extracted as strings
77
    """
78
    with open(file_name) as infile:
×
79
        content = infile.readlines()
×
80
    return extract_data_from_str_lst(str_lst=content, tag=tag, num_args=num_args)
×
81

82

83
class Logstatus(object):
1✔
84
    """
85
    Generic Parser for parsing output files by searching for a specific pattern structure and extracting the data that
86
    follows the pattern into the status_dict dictionary.
87

88
    Args:
89
        iter_levels (int): Levels of iteration - default = 1
90
    """
91

92
    def __init__(self, h5: Optional[Any] = None, iter_levels: int = 1) -> None:
1✔
93
        """
94
        Initialize the Logstatus object.
95

96
        Args:
97
            h5 (Optional[Any]): HDF5 object to store the dictionary in. Defaults to None.
98
            iter_levels (int): Levels of iteration. Defaults to 1.
99
        """
100
        if h5 is not None:
×
101
            h5.add_group("generic")
×
102
            h5.move_up()
×
103
            self.h5 = h5
×
104
            self.h5_group_data = h5.getGroup().logStatus
×
105

106
        self.status_dict = {}
×
107
        self.iter_levels = iter_levels
×
108
        self.iter = iter_levels * [0]
×
109
        self.store_as_vector = []
×
110
        self.h5_open = False
×
111

112
    def reset_iter(self, dim: int = 0) -> None:
1✔
113
        """
114
        Reset iteration level
115

116
        Args:
117
            dim (int): reset value - default = 0
118
        """
119
        for i in range(dim, self.iter_levels):
×
120
            self.iter[i] = 0
×
121

122
    def raise_iter(self, dim: int = 0) -> None:
1✔
123
        """
124
        Increase the iteration level
125

126
        Args:
127
            dim (int): position - default = 0
128
        """
129
        self.iter[dim] += 1
×
130

131
    def append(
1✔
132
        self, title: str, data_to_append: Union[list, dict], vec: bool = False
133
    ) -> None:
134
        """
135
        Append data to the LogStatus object status_dict dictionary
136

137
        Args:
138
            title (str): Title of the data to append
139
            data_to_append (Union[list, dict]): the data can be of various types
140
            vec (bool): [True/False] if the data is a single vector instead of a matrix or a tensor
141
        """
142
        if title in self.status_dict.keys():
×
143
            if vec:
×
144
                raise ValueError(
×
145
                    "For appending matrix rather than vector option needed!"
146
                )
147
            self.status_dict[title].append([list(self.iter), data_to_append])
×
148
        else:
149
            self.status_dict[title] = [[list(self.iter), data_to_append]]
×
150

151
    def to_hdf(self, hdf: "ProjectHDFio") -> None:
1✔
152
        """
153
        Store the LogStatus object status_dict dictionary in an HDF5 file
154

155
        Args:
156
            hdf (ProjectHDFio): HDF5 object to store the dictionary in.
157
        """
158
        for key, value in self.status_dict.items():
×
159
            if key in self.store_as_vector:
×
160
                if len(value) > 1:
×
161
                    raise ValueError(
×
162
                        "Multi-dimensional array cannot be saved as vector"
163
                    )
164
                hdf[key] = np.array(value[0][1])
×
165
            else:
166
                hdf[key] = np.array([val for _, val in value])
×
167

168
    def combine_xyz(
1✔
169
        self,
170
        x_key: str,
171
        y_key: str,
172
        z_key: str,
173
        combined_key: str,
174
        as_vector: bool = False,
175
    ) -> None:
176
        """
177
        Combine three lists representing the x,y,z coordinates, by accessing them from the status_dict dictionary,
178
        combining them, store them under the combined_key and remove the other three keys.
179

180
        Args:
181
            x_key (str): key of the x coordinates
182
            y_key (str): key of the y coordinates
183
            z_key (str): key of the z coordinates
184
            combined_key (str): name of the combined coordinates
185
            as_vector (bool): [True/False] if the combined coordinates should be stored as a single vector instead of a matrix. Defaults to False.
186
        """
187
        if (
×
188
            x_key in self.status_dict
189
            and y_key in self.status_dict
190
            and z_key in self.status_dict
191
        ):
192
            combined_lst = []
×
193
            if as_vector:
×
194
                time_x, val_x = self.status_dict[x_key][0]
×
195
                time_y, val_y = self.status_dict[y_key][0]
×
196
                time_z, val_z = self.status_dict[z_key][0]
×
197
                for val_t_x, val_t_y, val_t_z in zip(val_x, val_y, val_z):
×
198
                    combined_lst.append([time_x, [val_t_x, val_t_y, val_t_z]])
×
199
            else:
200
                for var_x, var_y, var_z in zip(
×
201
                    self.status_dict[x_key],
202
                    self.status_dict[y_key],
203
                    self.status_dict[z_key],
204
                ):
205
                    time_x, val_x = var_x
×
206
                    time_y, val_y = var_y
×
207
                    time_z, val_z = var_z
×
208
                    combined_lst.append(
×
209
                        [
210
                            time_x,
211
                            [
212
                                [val_t_x, val_t_y, val_t_z]
213
                                for val_t_x, val_t_y, val_t_z in zip(
214
                                    val_x, val_y, val_z
215
                                )
216
                            ],
217
                        ]
218
                    )
219
            del self.status_dict[x_key]
×
220
            del self.status_dict[y_key]
×
221
            del self.status_dict[z_key]
×
222
            self.status_dict[combined_key] = combined_lst
×
223

224
    def combine_mat(
1✔
225
        self,
226
        x_key: str,
227
        xy_key: str,
228
        xz_key: str,
229
        y_key: str,
230
        yz_key: str,
231
        z_key: str,
232
        combined_key: str,
233
    ) -> None:
234
        """
235
        Combine three lists representing the x,y,z coordinates, by accessing them from the status_dict dictionary,
236
        combining them, store them under the combined_key and remove the other three keys.
237

238
        Args:
239
            x_key (str): key of the x coordinates
240
            xy_key (str): key of the xy coordinates
241
            xz_key (str): key of the xz coordinates
242
            y_key (str): key of the y coordinates
243
            yz_key (str): key of the yz coordinates
244
            z_key (str): key of the z coordinates
245
            combined_key (str): name of the combined coordinates
246
        """
247
        if (
×
248
            x_key in self.status_dict
249
            and y_key in self.status_dict
250
            and z_key in self.status_dict
251
        ):
252
            combined_lst = []
×
253
            for var_xx, var_xy, var_xz, var_yy, var_yz, var_zz in zip(
×
254
                self.status_dict[x_key],
255
                self.status_dict[xy_key],
256
                self.status_dict[xz_key],
257
                self.status_dict[y_key],
258
                self.status_dict[yz_key],
259
                self.status_dict[z_key],
260
            ):
261
                time_xx, val_xx = var_xx
×
262
                time_xy, val_xy = var_xy
×
263
                time_xz, val_xz = var_xz
×
264
                time_yy, val_yy = var_yy
×
265
                time_yz, val_yz = var_yz
×
266
                time_zz, val_zz = var_zz
×
267
                combined_lst.append(
×
268
                    [
269
                        time_xx,
270
                        [
271
                            [
272
                                [var_t_xx, var_t_xy, var_t_xz],
273
                                [var_t_yx, var_t_yy, var_t_yz],
274
                                [var_t_zx, var_t_zy, var_t_zz],
275
                            ]
276
                            for var_t_xx, var_t_xy, var_t_xz, var_t_yx, var_t_yy, var_t_yz, var_t_zx, var_t_zy, var_t_zz in zip(
277
                                val_xx,
278
                                val_xy,
279
                                val_xz,
280
                                val_xy,
281
                                val_yy,
282
                                val_yz,
283
                                val_xz,
284
                                val_yz,
285
                                val_zz,
286
                            )
287
                        ],
288
                    ]
289
                )
290
            del self.status_dict[x_key]
×
291
            del self.status_dict[xy_key]
×
292
            del self.status_dict[xz_key]
×
293
            del self.status_dict[y_key]
×
294
            del self.status_dict[yz_key]
×
295
            del self.status_dict[z_key]
×
296
            self.status_dict[combined_key] = combined_lst
×
297

298
    def convert_unit(self, key: str, factor: float) -> None:
1✔
299
        """
300
        Convert the values of a specific key in the status_dict dictionary by multiplying them with a factor.
301

302
        Args:
303
            key (str): The key of the values to be converted.
304
            factor (float): The factor to multiply the values with.
305
        """
306
        if key in self.status_dict:
×
307
            return_lst = []
×
308
            for step in self.status_dict[key]:
×
309
                time, values = step
×
310
                return_lst.append([time, (np.array(values) * factor).tolist()])
×
311
            self.status_dict[key] = return_lst
×
312

313
    @staticmethod
1✔
314
    def extract_item(l_item: str) -> Tuple[str, Optional[List[str]]]:
1✔
315
        """
316
        Method to extract information from a single line - currently very specific for the Lammps output
317

318
        Args:
319
            l_item (str): line to extract information from
320

321
        Returns:
322
            Tuple[str, Optional[List[str]]]: the tag_string as string and the arguments as list
323
        """
324
        item_list = l_item.split()
×
325
        first_item = item_list[1]
×
326
        if first_item == "NUMBER":
×
327
            num_elements = 3
×
328
        elif first_item == "BOX":
×
329
            num_elements = 2
×
330
        else:
331
            num_elements = 1
×
332
        tag = item_list[1 : num_elements + 1]
×
333
        tag_string = " ".join(el for el in tag)
×
334
        if len(item_list) == num_elements + 1:
×
335
            args = None
×
336
        else:
337
            args = item_list[num_elements + 1 : :]
×
338
        return tag_string, args
×
339

340
    def extract_from_list(
1✔
341
        self,
342
        list_of_lines: List[str],
343
        tag_dict: Dict[str, Any],
344
        h5_dict: Optional[Dict[str, str]] = None,
345
        key_dict: Optional[Dict[str, str]] = None,
346
    ) -> None:
347
        """
348
        Main function of the LogStatus class to extract data from an output file by searching for the tag dictionary
349

350
        Args:
351
            list_of_lines (List[str]): List of lines from the output file
352
            tag_dict (Dict[str, Any]): Dictionary with tags/patterns as key and an additional dictionary to describe the data structure.
353
            h5_dict (Optional[Dict[str, str]]): Translation dictionary of output tags as keys to the tags used on the HDF5 file as values. Defaults to None.
354
            key_dict (Optional[Dict[str, str]]): Translation dictionary of python internal tags as keys to the output tags as values. Defaults to None.
355
        """
356
        val_item = {}
×
357
        tag_vals = {}
×
358

359
        tag = LogTag(tag_dict, h5_dict, key_dict)
×
360

361
        iterate_over_lines = iter(list_of_lines)
×
362
        for line_read in iterate_over_lines:
×
363
            while True:
×
364
                if tag.is_item(line_read):  # items):
×
365
                    tag_name = tag.tag_name
×
366
                    if tag.rows() == 0:  # read single line_read
×
367
                        tag.set_item(tag_vals, self)
×
368
                        try:
×
369
                            line_read = next(iterate_over_lines)
×
370
                        except StopIteration:
×
371
                            break
×
372
                    else:
373
                        for _ in range(tag.line_skip()):
×
374
                            line_read = next(iterate_over_lines)
×
375
                        if isinstance(tag.rows(), str):
×
376
                            i_line = 0
×
377
                            while True:
×
378
                                try:
×
379
                                    line_read = next(iterate_over_lines)
×
380
                                except StopIteration:
×
381
                                    break
×
382
                                if line_read.find(tag.rows().strip()) > -1:
×
383
                                    break
×
384
                                if "WARNING:" in line_read:
×
385
                                    break
×
386
                                val_line = [
×
387
                                    [
388
                                        ast.literal_eval(line)
389
                                        for line in line_read.split()
390
                                    ]
391
                                ]
392
                                if i_line == 0:
×
393
                                    val_array = np.array(val_line)
×
394
                                else:
395
                                    val_array = np.append(
×
396
                                        arr=val_array, values=val_line, axis=0
397
                                    )
398
                                i_line += 1
×
399

400
                        else:
401
                            for i_line in range(tag.rows()):
×
402
                                try:
×
403
                                    line_read = next(iterate_over_lines)
×
404
                                except StopIteration:
×
405
                                    break
×
406
                                val_line = [
×
407
                                    [
408
                                        ast.literal_eval(line)
409
                                        for line in line_read.split()
410
                                    ]
411
                                ]
412
                                if i_line == 0:
×
413
                                    val_array = np.array(val_line)
×
414
                                else:
415
                                    val_array = np.append(
×
416
                                        arr=val_array, values=val_line, axis=0
417
                                    )
418

419
                        if tag.is_func():
×
420
                            val_array = tag.apply_func(val_array)
×
421

422
                        val_item[tag_name] = val_array
×
423
                        if np.shape(val_array) == (1, 1):
×
424
                            self.append(tag.h5(), val_array[0, 0])
×
425
                        elif tag.test_split():
×
426
                            tag_list = None
×
427
                            if tag.split_tag:
×
428
                                tag_list = tag_name.split()
×
429
                            elif tag.split_arg:
×
430
                                if "header" not in tag_dict[tag_name].keys():
×
431
                                    tag_list = tag.val_list
×
432
                                else:
433
                                    tag_list = tag_dict[tag_name]["header"]
×
434
                            for i, t in enumerate(tag_list):
×
435
                                if "header" not in tag_dict[tag_name].keys():
×
436
                                    self.append(
×
437
                                        tag.translate(t), np.copy(val_array[:, i])
438
                                    )
439
                                else:
440
                                    self.append(t, np.copy(val_array[:, i]))
×
441
                        else:
442
                            self.append(tag.h5(), np.copy(val_array))
×
443
                else:
444
                    try:
×
445
                        line_read = next(iterate_over_lines)
×
446
                    except StopIteration:
×
447
                        break
×
448

449
    def extract_file(
1✔
450
        self,
451
        file_name: str,
452
        tag_dict: Dict[str, Any],
453
        h5_dict: Optional[Dict[str, str]] = None,
454
        key_dict: Optional[Dict[str, str]] = None,
455
    ) -> None:
456
        """
457
        Main function of the LogStatus class to extract data from an output file by searching for the tag dictionary
458

459
        Args:
460
            file_name (str): absolute path to the output file
461
            tag_dict (dict): Dictionary with tags/patterns as key and an additional dictionary to describe the data
462
                             structure. The data structure dictionary can contain the following keys:
463
                             - "arg": position of the argument - or dimension (":", ":,:")
464
                             - "type": Python data type
465
                             - "h5": HDF5 key to store the information
466
                             - "rows": number of rows from the line where the tag was found
467
                             - "splitTag": split the tag - [True/False]
468
                             - "splitArg": split the argument - [True/False]
469
                             - "lineSkip": skip a line
470
                             - "func": function to convert the data
471
            h5_dict (dict): Translation dictionary of output tags as keys to the tags used on the HDF5 file as values.
472
            key_dict (dict): Translation dictionary of python internal tags as keys to the output tags as values.
473
        """
474
        with open(file_name, "r") as f:
×
475
            content = f.readlines()
×
476
        self.extract_from_list(
×
477
            list_of_lines=content, tag_dict=tag_dict, h5_dict=h5_dict, key_dict=key_dict
478
        )
479

480

481
class LogTag(object):
1✔
482
    """
483
    LogTag object to parse for a specific pattern in the output file
484

485
    Args:
486
        tag_dict (Dict[str, Any]): Dictionary with tags/patterns as key and an additional dictionary to describe the data
487
                                   structure. The data structure dictionary can contain the following keys:
488
                                    - "arg": position of the argument - or dimension (":", ":,:")
489
                                    - "type": Python data type
490
                                    - "h5": HDF5 key to store the information
491
                                    - "rows": number of rows from the line where the tag was found
492
                                    - "splitTag": split the tag - [True/False]
493
                                    - "splitArg": split the argument - [True/False]
494
                                    - "lineSkip": skip a line
495
                                    - "func": function to convert the data
496
        h5_dict (Optional[Dict[str, str]]): Translation dictionary of output tags as keys to the tags used on the HDF5 file as values. Defaults to None.
497
        key_dict (Optional[Dict[str, str]]): Translation dictionary of python internal tags as keys to the output tags as values. Defaults to None.
498
    """
499

500
    def __init__(
1✔
501
        self,
502
        tag_dict: Dict[str, Any],
503
        h5_dict: Optional[Dict[str, str]] = None,
504
        key_dict: Optional[Dict[str, str]] = None,
505
    ) -> None:
506
        self._tag_dict = None
×
507
        self._tag_first_word = None
×
508
        self._current = None
×
509
        self._dyn_tags = None
×
510
        self._key_dict = None
×
511
        self._h5_dict = None
×
512
        self._tag_name = None
×
513
        self.tag_dict = tag_dict
×
514
        self.key_dict = key_dict
×
515
        self.h5_dict = h5_dict
×
516

517
    @property
1✔
518
    def current(self) -> Dict[str, Any]:
1✔
519
        """
520
        Get the current tag
521

522
        Returns:
523
            dict: current tag
524
        """
525
        return self._current
×
526

527
    @current.setter
1✔
528
    def current(self, tag_name: str) -> None:
1✔
529
        """
530
        Set the current tag
531

532
        Args:
533
            tag_name (str): current tag
534
        """
535
        if tag_name not in self.tag_dict.keys():
×
536
            raise ValueError("Unknown tag_name: " + tag_name)
×
537
        self._tag_name = tag_name
×
538
        self._current = self.tag_dict[tag_name]
×
539

540
    @property
1✔
541
    def tag_name(self) -> str:
1✔
542
        """
543
        Get tag name
544

545
        Returns:
546
            str: tag name
547
        """
548
        return self._tag_name
×
549

550
    @property
1✔
551
    def tag_dict(self) -> dict:
1✔
552
        """
553
        Get tag dictionary with tags/patterns as key and an additional dictionary to describe the data
554
        structure. The data structure dictionary can contain the following keys:
555
        - "arg": position of the argument - or dimension (":", ":,:")
556
        - "type": Python data type
557
        - "h5": HDF5 key to store the information
558
        - "rows": number of rows from the line where the tag was found
559
        - "splitTag": split the tag - [True/False]
560
        - "splitArg": split the argument - [True/False]
561
        - "lineSkip": skip a line
562
        - "func": function to convert the data
563

564
        Returns:
565
            dict: tag dictionary
566
        """
567
        return self._tag_dict
×
568

569
    @tag_dict.setter
1✔
570
    def tag_dict(self, tag_dict: dict) -> None:
1✔
571
        """
572
        Set tag dictionary with tags/patterns as key and an additional dictionary to describe the data
573
        structure. The data structure dictionary can contain the following keys:
574
        - "arg": position of the argument - or dimension (":", ":,:")
575
        - "type": Python data type
576
        - "h5": HDF5 key to store the information
577
        - "rows": number of rows from the line where the tag was found
578
        - "splitTag": split the tag - [True/False]
579
        - "splitArg": split the argument - [True/False]
580
        - "lineSkip": skip a line
581
        - "func": function to convert the data
582

583
        Args:
584
            tag_dict (dict): tag dictionary
585
        """
586
        self._tag_dict = tag_dict
×
587
        self._tag_first_word = tuple(self.tag_dict.keys())
×
588
        self.dyn_tags = tag_dict
×
589

590
    @property
1✔
591
    def tag_first_word(self) -> str:
1✔
592
        """
593
        Get first word of the tag
594

595
        Returns:
596
            str: first word
597
        """
598
        return self._tag_first_word
×
599

600
    @property
1✔
601
    def dyn_tags(self) -> dict:
1✔
602
        """
603
        Get dynamic tags
604

605
        Returns:
606
            dict: dynamic tags
607
        """
608
        return self._dyn_tags
×
609

610
    @dyn_tags.setter
1✔
611
    def dyn_tags(self, tag_dict: dict) -> None:
1✔
612
        """
613
        Set dynamic tags
614

615
        Args:
616
            tag_dict (dict): tag dictionary
617
        """
618
        dyn_tags = {}
×
619
        for w in tag_dict.keys():
×
620
            items = w.split()
×
621
            if items[0][:1] == "$":
×
622
                dyn_tags[w[1:]] = w
×
623
        self._dyn_tags = dyn_tags
×
624

625
    @property
1✔
626
    def key_dict(self) -> dict:
1✔
627
        """
628
        Get translation dictionary of python internal tags as keys to the output tags as values.
629

630
        Returns:
631
            dict: key dictionary
632
        """
633
        return self._key_dict
×
634

635
    @key_dict.setter
1✔
636
    def key_dict(self, key_dict: dict) -> None:
1✔
637
        """
638
        Set translation dictionary of python internal tags as keys to the output tags as values.
639

640
        Args:
641
            key_dict (dict): key dictionary
642
        """
643
        self._key_dict = key_dict
×
644

645
    @property
1✔
646
    def h5_dict(self) -> dict:
1✔
647
        """
648
        Get translation dictionary of output tags as keys to the tags used on the HDF5 file as values.
649

650
        Returns:
651
            dict: h5 dictionary
652
        """
653
        return self._h5_dict
×
654

655
    @h5_dict.setter
1✔
656
    def h5_dict(self, h5_dict: dict) -> None:
1✔
657
        """
658
        Set translation dictionary of output tags as keys to the tags used on the HDF5 file as values.
659

660
        Args:
661
            h5_dict (dict): h5 dictionary
662
        """
663
        self._h5_dict = h5_dict
×
664

665
    def is_item(self, item_line: str, start: int = 0) -> bool:
1✔
666
        """
667
        Check if the current line - item_line - matches one of the provided tags, if that is the case set the tag to be
668
        the current tag and update the val_list with the corresponding values.
669

670
        Args:
671
            item_line (str): Line of the output file
672
            start (int): Character to start with when parsing the item_line - default=0
673

674
        Returns:
675
            bool: [True/False]
676
        """
677
        line = item_line.strip()
×
678
        if not line.startswith(
×
679
            self.tag_first_word, start
680
        ):  # start -> line must start with tag
681
            return False
×
682
        tag = None
×
683
        for tag in self.tag_first_word:
×
684
            if start == line.find(tag, start):
×
685
                break
×
686

687
        items = [ls.strip() for ls in line[len(tag) :].split()]
×
688
        self.current = tag
×
689
        self.val_list = items
×
690
        return True
×
691

692
    def get_item(self, item: str, default: Any) -> Union[list, dict, int, float]:
1✔
693
        """
694
        If item is part of the current dictionary keys the corresponding value is returned otherwise the default is
695
        returned.
696

697
        Args:
698
            item (str): dictionary key
699
            default (list, dict, int, float): Default value
700

701
        Returns:
702
            list, dict, int, float: The values connected to the key item in the current dictionary and if item is not a
703
                                    key in the current dictionary return the default value.
704
        """
705
        if self.current is None:
×
706
            raise ValueError("current tag not defined!")
×
707
        if item in self.current.keys():
×
708
            return self.current[item]
×
709
        else:
710
            return default
×
711

712
    def h5(self) -> str:
1✔
713
        """
714
        Translate current tag to HDF5 tag using the tag dictionary
715

716
        Returns:
717
            str: hdf5 key name
718
        """
719
        return self.get_item(item="h5", default=self.tag_name)
×
720

721
    def translate(self, item: str) -> str:
1✔
722
        """
723
        Translate current tag to HDF5 tag using the h5_dict dictionary
724

725
        Args:
726
            item (str): Python tag
727

728
        Returns:
729
            str: HDF5 tag
730
        """
731
        if self.h5_dict is None:
×
732
            raise ValueError("h5_dict is None!" + item)
×
733
        if item in self.h5_dict.keys():
×
734
            return self.h5_dict[item]
×
735
        else:
736
            raise ValueError("tag not in h5_dict: " + item)
×
737

738
    def arg(self) -> str:
1✔
739
        """
740
        Get tag argument
741

742
        Returns:
743
            str: tag arguments
744
        """
745
        l_arg = self.get_item(item="arg", default=0)
×
746
        if isinstance(l_arg, str):
×
747
            return l_arg
×
748
        else:
749
            return str(l_arg)
×
750

751
    def line_skip(self) -> bool:
1✔
752
        """
753
        Check how many lines should be skipped.
754

755
        Returns:
756
            bool: [True/ False]
757
        """
758
        return bool(self.get_item(item="lineSkip", default=0))
×
759

760
    def rows(self) -> Union[int, str]:
1✔
761
        """
762
        Number of rows to parse
763

764
        Returns:
765
            int, str: number of rows
766
        """
767
        rows = self.get_item(item="rows", default=0)
×
768
        try:
×
769
            return int(rows)
×
770
        except ValueError:
×
771
            return rows
×
772

773
    def test_split(self) -> bool:
1✔
774
        """
775
        Check if the argument or the tag should be split - if "splitArg" or "splitTag" is included in the tag_dict
776
        dictionary.
777

778
        Returns:
779
            bool: [True/ False]
780
        """
781
        self.split_arg = self.get_item(item="splitArg", default=False)
×
782
        self.split_tag = self.get_item(item="splitTag", default=False)
×
783
        return self.split_arg or self.split_tag
×
784

785
    def is_func(self) -> bool:
1✔
786
        """
787
        Check if a function is defined to convert the data - if "func" is included in the tag_dict dictionary
788

789
        Returns:
790
            bool: [True/ False]
791
        """
792
        my_func = self.get_item(item="func", default=None)
×
793
        return my_func is not None
×
794

795
    def apply_func(
1✔
796
        self, val: Union[list, dict, int, float]
797
    ) -> Union[list, dict, int, float]:
798
        """
799
        Apply the function on a given value
800

801
        Args:
802
            val (dict, list, float, int): value to apply the function on
803

804
        Returns:
805
            dict, list, float, int: result of applying the function
806
        """
807
        my_func = self.get_item(item="func", default=None)
×
808
        if my_func is not None:
×
809
            return my_func(val)
×
810

811
    def set_item(
1✔
812
        self, tag_vals: dict, log_file: Logstatus
813
    ) -> Tuple[str, dict, int, bool]:
814
        """
815
        Set LogTag item
816

817
        Args:
818
            tag_vals (dict): tag value dictionary
819
            log_file (Logstatus): Logstatus object
820

821
        Returns:
822
            list: tag name, tag values, rows, line skip [True/False]
823
        """
824
        tag_name = self.tag_name
×
825
        if self.rows() == 0:
×
826
            if not len(self.arg()) == 1:
×
827
                val = []
×
828
                for i_item in ast.literal_eval(self.arg()):
×
829
                    val.append(ast.literal_eval("self.val_list[" + i_item + "]"))
×
830
            else:  # input is an array
831
                val = eval("self.val_list[" + self.arg() + "]")
×
832
            if isinstance(val, str):
×
833
                val = ast.literal_eval(val)
×
834
            tag_vals[tag_name] = val
×
835
            if len(self.arg()) == 1:
×
836
                log_file.append(self.h5(), data_to_append=val)
×
837
            else:
838
                for i_num, i_val in enumerate(val):
×
839
                    log_file.append(self.h5()[i_num], data_to_append=i_val)
×
840
            if tag_name in self.dyn_tags.keys():
×
841
                self.resolve_dynamic_variable(val)
×
842
        return tag_name, tag_vals, self.rows(), self.line_skip()
×
843

844
    def resolve_dynamic_variable(self, val: list) -> None:
1✔
845
        """
846
        Resolve dynamic variable using the key_dict dictionary
847

848
        Args:
849
            val: values to resolve
850
        """
851
        d_name = self.dyn_tags[self.tag_name]
×
852
        if self.key_dict is not None:
×
853
            val = [self.key_dict[v] for v in val if v in self.key_dict.keys()]
×
854
        resolved_name = " ".join(val)
×
855

856
        v = self.tag_dict[d_name]
×
857
        self.tag_dict[resolved_name] = v
×
858
        del self.tag_dict[d_name]
×
859
        self.dyn_tags = self.tag_dict
×
860
        self._tag_first_word = tuple(self.tag_dict.keys())
×
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