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
« 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
35from lxml import etree
36from os import chdir as os_chdir
37from textwrap import dedent
39from pathlib import Path
41from pyTooling.Common import getFullyQualifiedName
42from pyTooling.Decorators import export
44from pyEDAA.IPXACT import RootElement, Vlnv, PyIpxactException, __URI_MAP__, __DEFAULT_SCHEMA__
45from pyEDAA.IPXACT.Component import Component
48@export
49class IpxactFile:
50 """Represents a IP-XACT file."""
51 _vlnv: Vlnv #: VLNV unique identifier
52 _name: str #: Name
53 _description: str #: Description
55 def __init__(self, vlnv: Vlnv, name: str, description: str):
56 """Constructor"""
57 self._vlnv = vlnv
58 self._name = name
59 self._description = description
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'.")
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")
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'.")
84 ipxactFile = cls(vlnv, name, description)
85 return ipxactFile
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 """)
99 return buffer
102@export
103class Catalog(RootElement):
104 """Represents an IP-XACT catalog."""
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
116 def __init__(self, vlnv: Vlnv, description: str):
117 super().__init__(vlnv)
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 = []
129 @classmethod
130 def FromFile(cls, filePath : Path):
131 """Constructs an instance of ``Catalog`` from a file."""
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))
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
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
151 xmlParser = etree.XMLParser(remove_blank_text=True, encoding="utf-8")
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)
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.")
166 print("==" * 20)
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.")
187 print("==" * 20)
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)
194 return catalog
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
208 def ToXml(self) -> str:
209 """Converts the object's data into XML format."""
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 )
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"
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"
239 buffer += dedent("""\
240 </{xmlns}:catalog>
241 """)
243 return buffer.format(xmlns=__DEFAULT_SCHEMA__.NamespacePrefix)