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

140 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2024-11-17 01:13 +0000

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

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

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

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

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

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

7# |_| |___/ # 

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2017-2024 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 sys import version_info 

33from typing import List 

34 

35from lxml import etree 

36from os import chdir as os_chdir 

37from textwrap import dedent 

38 

39from pathlib import Path 

40 

41from pyTooling.Common import getFullyQualifiedName 

42from pyTooling.Decorators import export 

43 

44from pyEDAA.IPXACT import RootElement, Vlnv, PyIpxactException, __URI_MAP__, __DEFAULT_SCHEMA__ 

45from pyEDAA.IPXACT.Component import Component 

46 

47 

48@export 

49class IpxactFile: 

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

51 _vlnv: Vlnv #: VLNV unique identifier 

52 _name: str #: Name 

53 _description: str #: Description 

54 

55 def __init__(self, vlnv: Vlnv, name: str, description: str): 

56 """Constructor""" 

57 self._vlnv = vlnv 

58 self._name = name 

59 self._description = description 

60 

61 @classmethod 

62 def FromXml(cls, element): 

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

64 elementTag = etree.QName(element.tag) 

65 if elementTag.localname != "ipxactFile": 

66 raise PyIpxactException("Expected tag 'ipxactFile'.") 

67 

68 for element2 in element: 

69 element3 = etree.QName(element2) 

70 if element3.localname == "vlnv": 

71 vendor = element2.get("vendor") 

72 library = element2.get("library") 

73 name2 = element2.get("name") 

74 version = element2.get("version") 

75 

76 vlnv = Vlnv(vendor, library, name2, version) 

77 elif element3.localname == "name": 

78 name = element2.text 

79 elif element3.localname == "description": 

80 description = element2.text 

81 else: 

82 raise PyIpxactException(f"Unsupported tag '{element.localname}' in node 'ipxactFile'.") 

83 

84 ipxactFile = cls(vlnv, name, description) 

85 return ipxactFile 

86 

87 def ToXml(self, indent): 

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

89 _indent = "\t" * indent 

90 prefix = __DEFAULT_SCHEMA__.NamespacePrefix 

91 buffer = dedent(f"""\ 

92 {_indent}<{prefix}:ipxactFile> 

93 {_indent} {self._vlnv.ToXml(0)} 

94 {_indent} <{prefix}:name>{self._name}</{prefix}:name> 

95 {_indent} <{prefix}:description>{self._description}</{prefix}:description> 

96 {_indent}</{prefix}:ipxactFile> 

97 """) 

98 

99 return buffer 

100 

101 

102@export 

103class Catalog(RootElement): 

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

105 

106 _description: str 

107 _abstractionDefinitions: List 

108 _abstractors: List 

109 _busInterfaces: List 

110 _catalogs: List 

111 _components: List 

112 _designConfigurations: List 

113 _designs: List 

114 _generatorChains: List 

115 

116 def __init__(self, vlnv: Vlnv, description: str): 

117 super().__init__(vlnv) 

118 

119 self._description = description 

120 self._abstractionDefinitions = [] 

121 self._abstractors = [] 

122 self._busInterfaces = [] 

123 self._catalogs = [] 

124 self._components = [] 

125 self._designConfigurations = [] 

126 self._designs = [] 

127 self._generatorChains = [] 

128 

129 @classmethod 

130 def FromFile(cls, filePath : Path): 

131 """Constructs an instance of ``Catalog`` from a file.""" 

132 

133 if not filePath.exists(): 133 ↛ 134line 133 didn't jump to line 134 because the condition on line 133 was never true

134 raise PyIpxactException(f"File '{filePath}' not found.") from FileNotFoundError(str(filePath)) 

135 

136 try: 

137 with filePath.open("r", encoding="utf-8") as fileHandle: # TODO: why not open in binary? 

138 content = fileHandle.read() 

139 content = bytes(bytearray(content, encoding='utf-8')) 

140 except OSError as ex: 

141 raise PyIpxactException("Couldn't open '{0!s}'.".format(filePath)) from ex 

142 

143 schemaPath = Path("../lib/schema/ieee-1685-2014/index.xsd") 

144 try: 

145 with schemaPath.open("r", encoding="utf-8") as fileHandle: # TODO: why not opening as binary? 

146 schema = fileHandle.read() 

147 schema = bytes(bytearray(schema, encoding='utf-8')) 

148 except OSError as ex: 

149 raise PyIpxactException(f"Couldn't open '{schemaPath}'.") from ex 

150 

151 xmlParser = etree.XMLParser(remove_blank_text=True, encoding="utf-8") 

152 

153 schemaRoot = etree.XML(schema, xmlParser) 

154 schemaTree = etree.ElementTree(schemaRoot) 

155 xmlschema = etree.XMLSchema(schemaTree) 

156 root = etree.XML(content, xmlParser) 

157 rootTag = etree.QName(root.tag) 

158 

159 if not xmlschema.validate(root): 

160 raise PyIpxactException("The input IP-XACT file is not valid.") 

161 elif rootTag.namespace not in __URI_MAP__: 

162 raise PyIpxactException(f"The input IP-XACT file uses an unsupported namespace: '{rootTag.namespace}'.") 

163 elif rootTag.localname != "catalog": 

164 raise PyIpxactException("The input IP-XACT file is not a catalog file.") 

165 

166 print("==" * 20) 

167 

168 items = [] 

169 for rootElements in root: 

170 element = etree.QName(rootElements) 

171 if element.localname == "vendor": 

172 vendor = rootElements.text 

173 elif element.localname == "library": 

174 library = rootElements.text 

175 elif element.localname == "name": 

176 name = rootElements.text 

177 elif element.localname == "version": 

178 version = rootElements.text 

179 elif element.localname == "description": 

180 description = rootElements.text 

181 elif element.localname == "catalogs": 

182 for ipxactFileElement in rootElements: 

183 items.append(IpxactFile.FromXml(ipxactFileElement)) 

184 else: 

185 raise PyIpxactException(f"Unsupported tag '{element.localname}' at root-level.") 

186 

187 print("==" * 20) 

188 

189 vlnv = Vlnv(vendor=vendor, library=library, name=name, version=version) 

190 catalog = cls(vlnv, description=description) 

191 for item in items: 

192 catalog.AddItem(item) 

193 

194 return catalog 

195 

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

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

198 self._catalogs.append(item) 

199 elif isinstance(item, Component): 

200 self._components.append(item) 

201 else: 

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

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

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

205 raise ex 

206 

207 

208 def ToXml(self) -> str: 

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

210 

211 buffer = dedent("""\ 

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

213 <{xmlns}:catalog 

214 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

215 xmlns:{xmlns}="{schemaUri}" 

216 xsi:schemaLocation="{schemaUri} {schemaUrl}"> 

217 {versionedIdentifier} 

218 <{xmlns}:description>{description}</{xmlns}:description> 

219 """).format( 

220 xmlns=__DEFAULT_SCHEMA__.NamespacePrefix, 

221 schemaUri=__DEFAULT_SCHEMA__.SchemaUri, 

222 schemaUrl=__DEFAULT_SCHEMA__.SchemaUrl, 

223 versionedIdentifier=self._vlnv.ToXml(isVersionedIdentifier=True), 

224 description=self._description 

225 ) 

226 

227 if self._catalogs: 

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

229 for ipxactFile in self._catalogs: 

230 buffer += ipxactFile.ToXml(2) 

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

232 

233 if self._components: 

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

235 for ipxactFile in self._components: 

236 buffer += ipxactFile.ToXml(2) 

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

238 

239 buffer += dedent("""\ 

240 </{xmlns}:catalog> 

241 """) 

242 

243 return buffer.format(xmlns=__DEFAULT_SCHEMA__.NamespacePrefix)