Coverage for pyTooling / GenericPath / __init__.py: 97%
55 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-08 23:46 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-08 23:46 +0000
1# ==================================================================================================================== #
2# _____ _ _ ____ _ ____ _ _ #
3# _ __ _ |_ _|__ ___ | (_)_ __ __ _ / ___| ___ _ __ ___ _ __(_) ___| _ \ __ _| |_| |__ #
4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` || | _ / _ \ '_ \ / _ \ '__| |/ __| |_) / _` | __| '_ \ #
5# | |_) | |_| || | (_) | (_) | | | | | | (_| || |_| | __/ | | | __/ | | | (__| __/ (_| | |_| | | | #
6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)____|\___|_| |_|\___|_| |_|\___|_| \__,_|\__|_| |_| #
7# |_| |___/ |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2017-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"""A generic path to derive domain specific path libraries."""
32from typing import List, Optional as Nullable, Type
34try:
35 from pyTooling.Decorators import export
36 from pyTooling.MetaClasses import ExtendedType
37except (ImportError, ModuleNotFoundError): # pragma: no cover
38 print("[pyTooling.GenericPath] Could not import from 'pyTooling.*'!")
40 try:
41 from Decorators import export
42 from MetaClasses import ExtendedType
43 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover
44 print("[pyTooling.GenericPath] Could not import directly!")
45 raise ex
48@export
49class Base(metaclass=ExtendedType, mixin=True):
50 """Base-mixin-class for all :mod:`pyTooling.GenericPath` path elements."""
52 DELIMITER = "/" #: Path element delimiter sign.
54 _parent: Nullable["Base"] #: Reference to the parent object.
56 def __init__(self, parent: Nullable["Base"] = None) -> None:
57 """
58 Initialize the base-mixin-class with a parent reference.
60 :param parent: Optional parent reference.
61 """
62 self._parent = parent
65@export
66class RootMixIn(Base, mixin=True):
67 """Mixin-class for root elements in a path system."""
69 def __init__(self) -> None:
70 """
71 Initialize the mixin-class for a root element.
72 """
73 super().__init__(None)
76@export
77class ElementMixIn(Base, mixin=True):
78 """Mixin-class for elements in a path system."""
80 _elementName: str #: Name of the path element.
82 def __init__(self, parent: Base, elementName: str) -> None:
83 """
84 Initialize the mixin-class for a path element.
86 :param parent: Reference to a parent path element.
87 :param elementName: Name of the path element.
88 """
89 super().__init__(parent)
91 self._elementName = elementName
93 def __str__(self) -> str:
94 return self._elementName
97@export
98class PathMixIn(metaclass=ExtendedType, mixin=True):
99 """Mixin-class for a path."""
101 ELEMENT_DELIMITER = "/" #: Path element delimiter sign.
102 ROOT_DELIMITER = "/" #: Root element delimiter sign.
104 _isAbsolute: bool #: True, if the path is absolute.
105 _elements: List[ElementMixIn] #: List of path elements.
107 def __init__(self, elements: List[ElementMixIn], isAbsolute: bool) -> None:
108 """
109 Initialize the mixin-class for a path.
111 :param elements: Reference to a parent path element.
112 :param isAbsolute: Assign to true, if a path is absolute, otherwise false.
113 """
114 self._isAbsolute = isAbsolute
115 self._elements = elements
117 def __len__(self) -> int:
118 """
119 Returns the number of path elements.
121 :returns: Number of path elements.
122 """
123 return len(self._elements)
125 def __str__(self) -> str:
126 result = self.ROOT_DELIMITER if self._isAbsolute else ""
128 if len(self._elements) > 0: 128 ↛ 134line 128 didn't jump to line 134 because the condition on line 128 was always true
129 result = result + str(self._elements[0])
131 for element in self._elements[1:]:
132 result = result + self.ELEMENT_DELIMITER + str(element)
134 return result
136 @classmethod
137 def Parse(
138 cls,
139 path: str,
140 root: RootMixIn,
141 pathCls: Type["PathMixIn"],
142 elementCls: Type[ElementMixIn]
143 ) -> "PathMixIn":
144 """
145 Parses a string representation of a path and returns a path instance.
147 :param path: Path to be parsed.
148 :param root:
149 :param pathCls: Type used to create the path.
150 :param elementCls: Type used to create the path elements.
151 :return:
152 """
153 if path.startswith(cls.ROOT_DELIMITER):
154 isAbsolute = True
155 path = path[len(cls.ELEMENT_DELIMITER):]
156 else:
157 isAbsolute = False
159 parent = root
160 elements = []
161 for part in path.split(cls.ELEMENT_DELIMITER):
162 element = elementCls(parent, part)
163 parent = element
164 elements.append(element)
166 return pathCls(elements, isAbsolute)
169@export
170class SystemMixIn(metaclass=ExtendedType, mixin=True):
171 """Mixin-class for a path system."""