Coverage for ebcpy/utils/__init__.py: 100%
40 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-05-06 09:34 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-05-06 09:34 +0000
1"""
2Package containing utility functions used in different packages.
3Contains a statistics analyzer and a visualizer.
4"""
5import logging
6import os
7import re
8from pathlib import Path
9from typing import Union, List
12def setup_logger(name: str,
13 working_directory: Union[Path, str] = None,
14 level=logging.DEBUG):
15 """
16 Setup an class or module specific logger instance
17 to ensure readable output for users.
19 :param str name:
20 The name of the logger instance
21 :param str,Path working_directory:
22 The path where to store the logfile.
23 If None is given, logs are not stored.
24 :param str level:
25 The logging level, default is DEBUG
27 .. versionadded:: 0.1.7
28 """
29 logger = logging.getLogger(name=name)
30 # Set log-level
31 logger.setLevel(level=level)
32 # Check if logger was already instantiated. If so, return already.
33 if logger.handlers:
34 return logger
35 # Add handlers if not set already by logging.basicConfig and if path is specified
36 formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s %(name)s: %(message)s',
37 datefmt='%d.%m.%Y-%H:%M:%S')
38 if not logging.getLogger().hasHandlers():
39 console = logging.StreamHandler()
40 console.setFormatter(fmt=formatter)
41 logger.addHandler(hdlr=console)
42 if working_directory is not None:
43 os.makedirs(working_directory, exist_ok=True)
44 file_handler = logging.FileHandler(filename=working_directory.joinpath(f"{name}.log"))
45 file_handler.setFormatter(fmt=formatter)
46 logger.addHandler(hdlr=file_handler)
47 return logger
50def get_names(all_names: list, patterns: Union[str, List[str]]) -> List[str]:
51 """
52 Filter a list of candidate names by literal values or glob-style patterns.
54 This function returns all names from `all_names` that match the provided
55 `patterns`. Patterns may be a single string or a list of strings, and may
56 contain the wildcard `*` to match any sequence of characters. Literal names
57 without `*` must match exactly. The matching is performed in two steps:
58 1. Each pattern is translated to a regular expression if it contains `*`,
59 otherwise used as a literal match.
60 2. Any pattern that matches no names in `all_names` raises a `KeyError`.
62 The returned list preserves the order of `all_names`.
64 :param all_names: List of available names to filter.
65 :param patterns: A pattern or list of patterns (with optional `*` wildcards)
66 to match against `all_names`.
67 :return: A list of names from `all_names` that match any of the given patterns,
68 in original order.
69 :raises KeyError: If any pattern does not match at least one name.
70 """
71 if isinstance(patterns, str):
72 patterns = [patterns]
74 matched = set()
75 unmatched = []
76 for pat in patterns:
77 if '*' in pat:
78 regex = '^' + re.escape(pat).replace(r'\*', '.*') + '$'
79 hits = [k for k in all_names if re.match(regex, k)]
80 if hits:
81 matched.update(hits)
82 else:
83 unmatched.append(pat)
84 else:
85 if pat in all_names:
86 matched.add(pat)
87 else:
88 unmatched.append(pat)
90 if unmatched:
91 raise KeyError(
92 "The following variable names/patterns are not in the given .mat file: "
93 + ", ".join(unmatched)
94 )
95 # preserve original order
96 names = [var for var in all_names if var in matched]
97 return names