Coverage for pyTooling / Configuration / __init__.py: 95%
55 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-08 17:46 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-08 17:46 +0000
1# ==================================================================================================================== #
2# _____ _ _ ____ __ _ _ _ #
3# _ __ _ |_ _|__ ___ | (_)_ __ __ _ / ___|___ _ __ / _(_) __ _ _ _ _ __ __ _| |_(_) ___ _ __ #
4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` || | / _ \| '_ \| |_| |/ _` | | | | '__/ _` | __| |/ _ \| '_ \ #
5# | |_) | |_| || | (_) | (_) | | | | | | (_| || |__| (_) | | | | _| | (_| | |_| | | | (_| | |_| | (_) | | | | #
6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)____\___/|_| |_|_| |_|\__, |\__,_|_| \__,_|\__|_|\___/|_| |_| #
7# |_| |___/ |___/ |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2021-2026 Patrick Lehmann - Bötzingen, Germany #
15# #
16# Licensed under the Apache License, Version 2.0 (the "License"); #
17# you may not use this file except in compliance with the License. #
18# You may obtain a copy of the License at #
19# #
20# http://www.apache.org/licenses/LICENSE-2.0 #
21# #
22# Unless required by applicable law or agreed to in writing, software #
23# distributed under the License is distributed on an "AS IS" BASIS, #
24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
25# See the License for the specific language governing permissions and #
26# limitations under the License. #
27# #
28# SPDX-License-Identifier: Apache-2.0 #
29# ==================================================================================================================== #
30#
31"""
32Abstract configuration reader.
34.. hint::
36 See :ref:`high-level help <CONFIG>` for explanations and usage examples.
37"""
38from pathlib import Path
39from typing import Union, ClassVar, Iterator, Type, Optional as Nullable
41try:
42 from pyTooling.Decorators import export, readonly
43 from pyTooling.MetaClasses import ExtendedType, mixin
44 from pyTooling.Exceptions import ToolingException
45except (ImportError, ModuleNotFoundError): # pragma: no cover
46 print("[pyTooling.Configuration] Could not import from 'pyTooling.*'!")
48 try:
49 from Decorators import export, readonly
50 from MetaClasses import ExtendedType, mixin
51 from Exceptions import ToolingException
52 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover
53 print("[pyTooling.Configuration] Could not import directly!")
54 raise ex
57__all__ = ["KeyT", "NodeT", "ValueT"]
60KeyT = Union[str, int] #: Type variable for keys.
61NodeT = Union["Dictionary", "Sequence"] #: Type variable for nodes.
62ValueT = Union[NodeT, str, int, float] #: Type variable for values.
65@export
66class ConfigurationException(ToolingException):
67 """Base-exception of all exceptions raised by :mod:`pyTooling.Configuration`."""
70@export
71class Node(metaclass=ExtendedType, slots=True):
72 """Abstract node in a configuration data structure."""
74 DICT_TYPE: ClassVar[Type["Dictionary"]] #: Type reference used when instantiating new dictionaries
75 SEQ_TYPE: ClassVar[Type["Sequence"]] #: Type reference used when instantiating new sequences
76 _root: "Configuration" #: Reference to the root node.
77 _parent: "Dictionary" #: Reference to a parent node.
79 def __init__(self, root: "Configuration" = None, parent: Nullable[NodeT] = None) -> None:
80 """
81 Initializes a node.
83 :param root: Reference to the root node.
84 :param parent: Reference to the parent node.
85 """
86 self._root = root
87 self._parent = parent
89 def __len__(self) -> int: # type: ignore[empty-body]
90 """
91 Returns the number of sub-elements.
93 :returns: Number of sub-elements.
94 """
96 def __getitem__(self, key: KeyT) -> ValueT: # type: ignore[empty-body]
97 """
98 Access an element in the node by index or key.
100 :param key: Index or key of the element.
101 :returns: A node (sequence or dictionary) or scalar value (int, float, str).
102 """
103 raise NotImplementedError()
105 def __setitem__(self, key: KeyT, value: ValueT) -> None: # type: ignore[empty-body]
106 """
107 Set an element in the node by index or key.
109 :param key: Index or key of the element.
110 :param value: Value to set
111 """
112 raise NotImplementedError()
114 def __iter__(self) -> Iterator[ValueT]: # type: ignore[empty-body]
115 """
116 Returns an iterator to iterate a node.
118 :returns: Node iterator.
119 """
120 raise NotImplementedError()
122 @property
123 def Key(self) -> KeyT:
124 raise NotImplementedError()
126 @Key.setter
127 def Key(self, value: KeyT) -> None:
128 raise NotImplementedError()
130 def QueryPath(self, query: str) -> ValueT: # type: ignore[empty-body]
131 """
132 Return a node or value based on a path description to that node or value.
134 :param query: String describing the path to the node or value.
135 :returns: A node (sequence or dictionary) or scalar value (int, float, str).
136 """
137 raise NotImplementedError()
140@export
141@mixin
142class Dictionary(Node):
143 """Abstract dictionary node in a configuration."""
145 def __init__(self, root: "Configuration" = None, parent: Nullable[NodeT] = None) -> None:
146 """
147 Initializes a dictionary.
149 :param root: Reference to the root node.
150 :param parent: Reference to the parent node.
151 """
152 Node.__init__(self, root, parent)
154 def __contains__(self, key: KeyT) -> bool: # type: ignore[empty-body]
155 raise NotImplementedError()
158@export
159@mixin
160class Sequence(Node):
161 """Abstract sequence node in a configuration."""
163 def __init__(self, root: "Configuration" = None, parent: Nullable[NodeT] = None) -> None:
164 """
165 Initializes a sequence.
167 :param root: Reference to the root node.
168 :param parent: Reference to the parent node.
169 """
170 Node.__init__(self, root, parent)
172 def __getitem__(self, index: int) -> ValueT: # type: ignore[empty-body]
173 raise NotImplementedError()
175 def __setitem__(self, index: int, value: ValueT) -> None: # type: ignore[empty-body]
176 raise NotImplementedError()
179setattr(Node, "DICT_TYPE", Dictionary)
180setattr(Node, "SEQ_TYPE", Sequence)
183@export
184@mixin
185class Configuration(Node):
186 """Abstract root node in a configuration."""
188 _configFile: Path #: Path to the configuration file.
190 def __init__(self, configFile: Path, root: "Configuration" = None, parent: Nullable[NodeT] = None) -> None:
191 """
192 Initializes a configuration.
194 :param configFile: Configuration file.
195 :param root: Reference to the root node.
196 :param parent: Reference to the parent node.
197 """
198 Node.__init__(self, root, parent)
199 self._configFile = configFile
201 @readonly
202 def ConfigFile(self) -> Path:
203 """
204 Read-only property to access the configuration file's path.
206 :returns: Path to the configuration file.
207 """
208 return self._configFile