Coverage for pyEDAA/IPXACT/Catalog.py: 71%

119 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-05-30 22:17 +0000

1# ==================================================================================================================== # 

2# _____ ____ _ _ ___ ______ __ _ ____ _____ # 

3# _ __ _ _| ____| _ \ / \ / \ |_ _| _ \ \/ / / \ / ___|_ _| # 

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | || |_) \ / / _ \| | | | # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _ | || __// \ / ___ \ |___ | | # 

6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)___|_| /_/\_\/_/ \_\____| |_| # 

7# |_| |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2017-2025 Patrick Lehmann - Bötzingen, Germany # 

15# Copyright 2016-2016 Patrick Lehmann - Dresden, Germany # 

16# # 

17# Licensed under the Apache License, Version 2.0 (the "License"); # 

18# you may not use this file except in compliance with the License. # 

19# You may obtain a copy of the License at # 

20# # 

21# http://www.apache.org/licenses/LICENSE-2.0 # 

22# # 

23# Unless required by applicable law or agreed to in writing, software # 

24# distributed under the License is distributed on an "AS IS" BASIS, # 

25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

26# See the License for the specific language governing permissions and # 

27# limitations under the License. # 

28# # 

29# SPDX-License-Identifier: Apache-2.0 # 

30# ==================================================================================================================== # 

31# 

32from pathlib import Path 

33from sys import version_info 

34from textwrap import dedent 

35from typing import List, Dict, Optional as Nullable, ClassVar 

36 

37from lxml.etree import QName, _Element 

38 

39from pyTooling.Decorators import export, readonly 

40from pyTooling.Common import getFullyQualifiedName 

41 

42from pyEDAA.IPXACT import NamedElement, RootElement, VLNV, IPXACTException, __DEFAULT_SCHEMA__, IPXACTSchema, Element 

43from pyEDAA.IPXACT.Component import Component 

44 

45 

46@export 

47class IpxactFile(NamedElement): 

48 """Represents a IP-XACT file.""" 

49 

50 _name: str #: Name 

51 _description: str #: Description 

52 

53 def __init__(self, vlnv: VLNV, name: str, description: str): 

54 """ 

55 Instantiates an ipxactFile structure. 

56 

57 :param vlnv: A Vendor-Library-Name-Version unique identified. 

58 :param name: Name of the IP-XACT file. 

59 :param description: A description text. 

60 :raises TypeError: If parameter vlnv is not a VLNV. 

61 :raises TypeError: If parameter name is not a string. 

62 :raises ValueError: If parameter name is empty. 

63 :raises TypeError: If parameter description is not a string. 

64 :raises ValueError: If parameter description is empty. 

65 """ 

66 super().__init__(vlnv) 

67 

68 if not isinstance(name, str): 68 ↛ 69line 68 didn't jump to line 69 because the condition on line 68 was never true

69 ex = TypeError(f"Parameter 'name' is not a string.") 

70 if version_info >= (3, 11): # pragma: no cover 

71 ex.add_note(f"Got type '{getFullyQualifiedName(name)}'.") 

72 raise ex 

73 elif name == "": 73 ↛ 74line 73 didn't jump to line 74 because the condition on line 73 was never true

74 raise ValueError(f"Parameter 'name' is empty.") 

75 

76 if not isinstance(description, str): 76 ↛ 77line 76 didn't jump to line 77 because the condition on line 76 was never true

77 ex = TypeError(f"Parameter 'description' is not a string.") 

78 if version_info >= (3, 11): # pragma: no cover 

79 ex.add_note(f"Got type '{getFullyQualifiedName(description)}'.") 

80 raise ex 

81 elif description == "": 81 ↛ 82line 81 didn't jump to line 82 because the condition on line 81 was never true

82 raise ValueError(f"Parameter 'description' is empty.") 

83 

84 self._vlnv = vlnv 

85 self._name = name 

86 self._description = description 

87 

88 @classmethod 

89 def FromXml(cls, ipxactFileElement): 

90 """Constructs an instance of ``IpxactFile`` from an lxml element.""" 

91 

92 elementTag = QName(ipxactFileElement.tag) 

93 if elementTag.localname != "ipxactFile": 93 ↛ 94line 93 didn't jump to line 94 because the condition on line 93 was never true

94 raise IPXACTException("Expected tag 'ipxactFile'.") 

95 

96 vlnv = None 

97 name = None 

98 description = None 

99 for subElement in ipxactFileElement: 

100 element = QName(subElement) 

101 if element.localname == "vlnv": 

102 vendor = subElement.get("vendor") 

103 library = subElement.get("library") 

104 name2 = subElement.get("name") 

105 version = subElement.get("version") 

106 

107 vlnv = VLNV(vendor, library, name2, version) 

108 elif element.localname == "name": 

109 name = subElement.text 

110 elif element.localname == "description": 110 ↛ 113line 110 didn't jump to line 113 because the condition on line 110 was always true

111 description = subElement.text 

112 else: 

113 raise IPXACTException(f"Unsupported tag '{ipxactFileElement.localname}' in node 'ipxactFile'.") 

114 

115 ipxactFile = cls(vlnv, name, description) 

116 return ipxactFile 

117 

118 def ToXml(self, indent: int = 0, schema: IPXACTSchema = __DEFAULT_SCHEMA__): 

119 """Converts the object's data into XML format.""" 

120 # WORKAROUND: 

121 # Python <=3.11: 

122 # {'\t' * indent} is not supported by Python before 3.12 due to a backslash within {...} 

123 indent = "\t" * indent 

124 xmlns = schema.NamespacePrefix 

125 return dedent(f"""\ 

126 {indent}<{xmlns}:ipxactFile> 

127 {indent}\t{self._vlnv.ToXml(0, schema)} 

128 {indent}\t<{xmlns}:name>{self._name}</{xmlns}:name> 

129 {indent}\t<{xmlns}:description>{self._description}</{xmlns}:description> 

130 {indent}</{xmlns}:ipxactFile> 

131 """) 

132 

133 

134@export 

135class Catalog(RootElement): 

136 """Represents an IP-XACT catalog.""" 

137 

138 _rootTagName: ClassVar[str] = "catalog" 

139 

140 _abstractionDefinitions: List 

141 _abstractors: List 

142 _busInterfaces: List 

143 _catalogs: Dict[VLNV, IpxactFile] 

144 _components: List 

145 _designConfigurations: List 

146 _designs: List 

147 _generatorChains: List 

148 

149 def __init__( 

150 self, 

151 catalogFile: Nullable[Path] = None, 

152 parse: bool = False, 

153 vlnv: Nullable[VLNV] = None, 

154 description: Nullable[str] = None 

155 ): 

156 self._abstractionDefinitions = [] 

157 self._abstractors = [] 

158 self._busInterfaces = [] 

159 self._catalogs = {} 

160 self._components = [] 

161 self._designConfigurations = [] 

162 self._designs = [] 

163 self._generatorChains = [] 

164 

165 super().__init__(catalogFile, parse, vlnv, description) 

166 

167 def Parse(self, element: _Element) -> None: 

168 elementLocalname = QName(element).localname 

169 if elementLocalname == "catalogs": 

170 for ipxactFileElement in element: 

171 self.AddItem(IpxactFile.FromXml(ipxactFileElement)) 

172 elif elementLocalname == "abstractionDefinitions": 

173 pass 

174 elif elementLocalname == "components": 

175 pass 

176 elif elementLocalname == "abstractors": 

177 pass 

178 elif elementLocalname == "designs": 

179 pass 

180 elif elementLocalname == "designConfigurations": 

181 pass 

182 elif elementLocalname == "generatorChains": 182 ↛ 185line 182 didn't jump to line 185 because the condition on line 182 was always true

183 pass 

184 else: 

185 raise IPXACTException(f"Unsupported tag '{elementLocalname}' at root-level.") 

186 

187 def AddItem(self, item) -> None: 

188 if isinstance(item, IpxactFile): 188 ↛ 190line 188 didn't jump to line 190 because the condition on line 188 was always true

189 self._catalogs[item.VLNV] = item 

190 elif isinstance(item, Component): 

191 self._components.append(item) 

192 else: 

193 ex = TypeError(f"Parameter 'item' is neither a 'IpxactFile' nor a 'Component'.") 

194 if version_info >= (3, 11): # pragma: no cover 

195 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") 

196 raise ex 

197 

198 def ToXml(self, schema: IPXACTSchema = __DEFAULT_SCHEMA__) -> str: 

199 """Converts the object's data into XML format.""" 

200 

201 xmlns = schema.NamespacePrefix 

202 buffer = dedent(f"""\ 

203 <?xml version="1.0" encoding="UTF-8"?> 

204 <{xmlns}:catalog 

205 \txmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

206 \txmlns:{xmlns}="{schema.SchemaUri}" 

207 \txsi:schemaLocation="{schema.SchemaUri} {schema.SchemaUrl}"> 

208 {self._vlnv.ToXml(schema, isVersionedIdentifier=True)} 

209 \t<{xmlns}:description>{self._description}</{xmlns}:description> 

210 """) 

211 

212 if self._catalogs: 

213 buffer += f"\t<{xmlns}:catalogs>\n" 

214 for ipxactFile in self._catalogs: 

215 buffer += ipxactFile.ToXml(2, schema) 

216 buffer += f"\t</{xmlns}:catalogs>\n" 

217 

218 if self._components: 

219 buffer += f"\t<{xmlns}:components>\n" 

220 for ipxactFile in self._components: 

221 buffer += ipxactFile.ToXml(2, schema) 

222 buffer += f"\t</{xmlns}:components>\n" 

223 

224 buffer += dedent(f"""\ 

225 </{xmlns}:catalog> 

226 """) 

227 

228 return buffer 

229 

230 @readonly 

231 def Catalogs(self) -> Dict[VLNV, IpxactFile]: 

232 return self._catalogs