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

111 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-25 17:18 +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# 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 textwrap import dedent 

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

35 

36from lxml.etree import QName, _Element 

37 

38from pyTooling.Decorators import export, readonly 

39from pyTooling.Common import getFullyQualifiedName 

40 

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

42from pyEDAA.IPXACT.Component import Component 

43 

44 

45@export 

46class IpxactFile(NamedElement): 

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

48 

49 _name: str #: Name 

50 _description: str #: Description 

51 

52 def __init__(self, vlnv: VLNV, name: str, description: str) -> None: 

53 """ 

54 Instantiates an ipxactFile structure. 

55 

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

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

58 :param description: A description text. 

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

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

61 :raises ValueError: If parameter name is empty. 

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

63 :raises ValueError: If parameter description is empty. 

64 """ 

65 super().__init__(vlnv) 

66 

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

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

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

70 raise ex 

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

72 raise ValueError("Parameter 'name' is empty.") 

73 

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

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

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

77 raise ex 

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

79 raise ValueError("Parameter 'description' is empty.") 

80 

81 self._vlnv = vlnv 

82 self._name = name 

83 self._description = description 

84 

85 @classmethod 

86 def FromXml(cls, ipxactFileElement): 

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

88 

89 elementTag = QName(ipxactFileElement.tag) 

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

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

92 

93 vlnv = None 

94 name = None 

95 description = None 

96 for subElement in ipxactFileElement: 

97 element = QName(subElement) 

98 if element.localname == "vlnv": 

99 vendor = subElement.get("vendor") 

100 library = subElement.get("library") 

101 name2 = subElement.get("name") 

102 version = subElement.get("version") 

103 

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

105 elif element.localname == "name": 

106 name = subElement.text 

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

108 description = subElement.text 

109 else: 

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

111 

112 ipxactFile = cls(vlnv, name, description) 

113 return ipxactFile 

114 

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

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

117 # WORKAROUND: 

118 # Python <=3.11: 

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

120 indent = "\t" * indent 

121 xmlns = schema.NamespacePrefix 

122 return dedent(f"""\ 

123 {indent}<{xmlns}:ipxactFile> 

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

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

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

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

128 """) 

129 

130 

131@export 

132class Catalog(RootElement): 

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

134 

135 _ROOT_TAG_NAME: ClassVar[str] = "catalog" 

136 

137 _abstractionDefinitions: List 

138 _abstractors: List 

139 _busInterfaces: List 

140 _catalogs: Dict[VLNV, IpxactFile] 

141 _components: List 

142 _designConfigurations: List 

143 _designs: List 

144 _generatorChains: List 

145 

146 def __init__( 

147 self, 

148 catalogFile: Nullable[Path] = None, 

149 parse: bool = False, 

150 vlnv: Nullable[VLNV] = None, 

151 description: Nullable[str] = None 

152 ) -> None: 

153 self._abstractionDefinitions = [] 

154 self._abstractors = [] 

155 self._busInterfaces = [] 

156 self._catalogs = {} 

157 self._components = [] 

158 self._designConfigurations = [] 

159 self._designs = [] 

160 self._generatorChains = [] 

161 

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

163 

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

165 elementLocalname = QName(element).localname 

166 if elementLocalname == "catalogs": 

167 for ipxactFileElement in element: 

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

169 elif elementLocalname == "abstractionDefinitions": 

170 pass 

171 elif elementLocalname == "components": 

172 pass 

173 elif elementLocalname == "abstractors": 

174 pass 

175 elif elementLocalname == "designs": 

176 pass 

177 elif elementLocalname == "designConfigurations": 

178 pass 

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

180 pass 

181 else: 

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

183 

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

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

186 self._catalogs[item.VLNV] = item 

187 elif isinstance(item, Component): 

188 self._components.append(item) 

189 else: 

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

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

192 raise ex 

193 

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

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

196 

197 xmlns = schema.NamespacePrefix 

198 buffer = dedent(f"""\ 

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

200 <{xmlns}:catalog 

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

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

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

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

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

206 """) 

207 

208 if self._catalogs: 

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

210 for ipxactFile in self._catalogs: 

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

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

213 

214 if self._components: 

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

216 for ipxactFile in self._components: 

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

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

219 

220 buffer += dedent(f"""\ 

221 </{xmlns}:catalog> 

222 """) 

223 

224 return buffer 

225 

226 @readonly 

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

228 return self._catalogs