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