Coverage for ebcpy/utils/__init__.py: 100%
52 statements
« prev ^ index » next coverage.py v7.4.4, created at 2026-05-29 13:01 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2026-05-29 13:01 +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(
52 all_names: list,
53 patterns: Union[str, List[str]],
54 exclude: Union[str, List[str]] = None
55) -> List[str]:
56 """
57 Filter a list of candidate names by literal values or glob-style patterns,
58 optionally excluding names that match exclusion patterns.
60 This function returns all names from ``all_names`` that match the provided
61 ``patterns`` and do not match any of the ``exclude`` patterns.
62 Patterns may be a single string or a list of strings, and may
63 contain the wildcard ``*`` to match any sequence of characters. Literal names
64 without ``*`` must match exactly.
66 The returned list preserves the order of ``all_names``.
68 :param list all_names:
69 List of available names to filter.
70 :param str,list[str] patterns:
71 A pattern or list of patterns (with optional ``*`` wildcards)
72 to match against ``all_names``.
73 :param str,list[str] exclude:
74 A pattern or list of patterns to exclude from the results.
75 Names matching any exclusion pattern are removed after the
76 inclusion step. Default is None (no exclusion).
77 :return: A list of names from ``all_names`` that match any of the given
78 patterns and none of the exclusion patterns, in original order.
79 :rtype: list[str]
80 :raises warning: If any inclusion pattern does not match at least one name.
82 Example:
84 >>> names = ["wall.layer[1].T", "wall.layer[2].T", "wall.layer[1].Q_flow"]
85 >>> get_names(names, "wall.layer[*].T")
86 ['wall.layer[1].T', 'wall.layer[2].T']
87 >>> get_names(names, "wall.layer[*].*", exclude="*Q_flow")
88 ['wall.layer[1].T', 'wall.layer[2].T']
89 """
90 if isinstance(patterns, str):
91 patterns = [patterns]
93 matched = set()
94 unmatched = []
95 for pat in patterns:
96 if '*' in pat:
97 regex = '^' + re.escape(pat).replace(r'\*', '.*') + '$'
98 hits = [k for k in all_names if re.match(regex, k)]
99 if hits:
100 matched.update(hits)
101 else:
102 unmatched.append(pat)
103 else:
104 if pat in all_names:
105 matched.add(pat)
106 else:
107 unmatched.append(pat)
109 if unmatched:
110 warnings.warn(
111 "The following variable names/patterns are not in the given .mat file: "
112 + ", ".join(unmatched)
113 )
115 # Apply exclusion patterns
116 if exclude is not None:
117 if isinstance(exclude, str):
118 exclude = [exclude]
119 excluded = set()
120 for pat in exclude:
121 if '*' in pat:
122 regex = '^' + re.escape(pat).replace(r'\*', '.*') + '$'
123 excluded.update(k for k in matched if re.match(regex, k))
124 else:
125 if pat in matched:
126 excluded.add(pat)
127 matched -= excluded
129 # Preserve original order
130 names = [var for var in all_names if var in matched]
131 return names