Coverage for pyTooling/GenericPath/__init__.py: 97%

55 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-22 21:29 +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""" 

32A generic path to derive domain specific path libraries. 

33 

34.. seealso:: 

35 

36 :mod:`pyTooling.GenericPath.URL` 

37 |rarr| A URL as a domain-specific path. 

38 :mod:`pyTooling.Configuration` 

39 |rarr| Path expressions addressing a node in a configuration. 

40""" 

41from __future__ import annotations 

42 

43from typing import ClassVar, Optional as Nullable 

44 

45from pyTooling.Decorators import export 

46from pyTooling.MetaClasses import ExtendedType 

47 

48 

49@export 

50class Base(metaclass=ExtendedType, mixin=True): 

51 """Base-mixin-class for all :mod:`pyTooling.GenericPath` path elements.""" 

52 

53 DELIMITER: ClassVar[str] = "/" #: Path element delimiter sign. 

54 

55 _parent: Nullable[Base] #: Reference to the parent object. 

56 

57 def __init__(self, parent: Nullable[Base] = None) -> None: 

58 """ 

59 Initialize the base-mixin-class with a parent reference. 

60 

61 :param parent: Optional, parent reference. 

62 """ 

63 self._parent = parent 

64 

65 

66@export 

67class RootMixIn(Base, mixin=True): 

68 """Mixin-class for root elements in a path system.""" 

69 

70 def __init__(self) -> None: 

71 """ 

72 Initialize the mixin-class for a root element. 

73 """ 

74 super().__init__(None) 

75 

76 

77@export 

78class ElementMixIn(Base, mixin=True): 

79 """Mixin-class for elements in a path system.""" 

80 

81 _elementName: str #: Name of the path element. 

82 

83 def __init__(self, parent: Base, elementName: str) -> None: 

84 """ 

85 Initialize the mixin-class for a path element. 

86 

87 :param parent: Optional, reference to a parent path element. 

88 :param elementName: Name of the path element. 

89 """ 

90 super().__init__(parent) 

91 

92 self._elementName = elementName 

93 

94 def __str__(self) -> str: 

95 """ 

96 Return a string representation of this path element. 

97 

98 :returns: The element's name. 

99 """ 

100 return self._elementName 

101 

102 

103@export 

104class PathMixIn(metaclass=ExtendedType, mixin=True): 

105 """Mixin-class for a path.""" 

106 

107 ELEMENT_DELIMITER: ClassVar[str] = "/" #: Path element delimiter sign. 

108 ROOT_DELIMITER: ClassVar[str] = "/" #: Root element delimiter sign. 

109 

110 _isAbsolute: bool #: True, if the path is absolute. 

111 _elements: list[ElementMixIn] #: List of path elements. 

112 

113 def __init__(self, elements: list[ElementMixIn], isAbsolute: bool) -> None: 

114 """ 

115 Initialize the mixin-class for a path. 

116 

117 :param elements: Reference to a parent path element. 

118 :param isAbsolute: ``True``, if the path is absolute, otherwise ``False``. 

119 """ 

120 self._isAbsolute = isAbsolute 

121 self._elements = elements 

122 

123 def __len__(self) -> int: 

124 """ 

125 Returns the number of path elements. 

126 

127 :returns: Number of path elements. 

128 """ 

129 return len(self._elements) 

130 

131 def __str__(self) -> str: 

132 """ 

133 Return a string representation of this path. 

134 

135 :returns: The path's elements, joined by the delimiter, prefixed by the root delimiter if the path is absolute. 

136 """ 

137 result = self.ROOT_DELIMITER if self._isAbsolute else "" 

138 

139 if len(self._elements) > 0: 139 ↛ 145line 139 didn't jump to line 145 because the condition on line 139 was always true

140 result = result + str(self._elements[0]) 

141 

142 for element in self._elements[1:]: 

143 result = result + self.ELEMENT_DELIMITER + str(element) 

144 

145 return result 

146 

147 @classmethod 

148 def Parse( 

149 cls, 

150 path: str, 

151 root: RootMixIn, 

152 pathCls: type[PathMixIn], 

153 elementCls: type[ElementMixIn] 

154 ) -> PathMixIn: 

155 """ 

156 Parses a string representation of a path and returns a path instance. 

157 

158 :param path: Path to be parsed. 

159 :param root: Root element the parsed path is relative to. 

160 :param pathCls: Type used to create the path. 

161 :param elementCls: Type used to create the path elements. 

162 :returns: A path instance of type ``pathCls``. 

163 """ 

164 if path.startswith(cls.ROOT_DELIMITER): 

165 isAbsolute = True 

166 path = path[len(cls.ELEMENT_DELIMITER):] 

167 else: 

168 isAbsolute = False 

169 

170 parent = root 

171 elements = [] 

172 for part in path.split(cls.ELEMENT_DELIMITER): 

173 element = elementCls(parent, part) 

174 parent = element 

175 elements.append(element) 

176 

177 return pathCls(elements, isAbsolute) 

178 

179 

180@export 

181class SystemMixIn(metaclass=ExtendedType, mixin=True): 

182 """Mixin-class for a path system."""