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
« 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
37from lxml.etree import QName, _Element
39from pyTooling.Decorators import export, readonly
40from pyTooling.Common import getFullyQualifiedName
42from pyEDAA.IPXACT import NamedElement, RootElement, VLNV, IPXACTException, __DEFAULT_SCHEMA__, IPXACTSchema, Element
43from pyEDAA.IPXACT.Component import Component
46@export
47class IpxactFile(NamedElement):
48 """Represents a IP-XACT file."""
50 _name: str #: Name
51 _description: str #: Description
53 def __init__(self, vlnv: VLNV, name: str, description: str):
54 """
55 Instantiates an ipxactFile structure.
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)
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.")
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.")
84 self._vlnv = vlnv
85 self._name = name
86 self._description = description
88 @classmethod
89 def FromXml(cls, ipxactFileElement):
90 """Constructs an instance of ``IpxactFile`` from an lxml element."""
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'.")
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")
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'.")
115 ipxactFile = cls(vlnv, name, description)
116 return ipxactFile
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 """)
134@export
135class Catalog(RootElement):
136 """Represents an IP-XACT catalog."""
138 _rootTagName: ClassVar[str] = "catalog"
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
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 = []
165 super().__init__(catalogFile, parse, vlnv, description)
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.")
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
198 def ToXml(self, schema: IPXACTSchema = __DEFAULT_SCHEMA__) -> str:
199 """Converts the object's data into XML format."""
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 """)
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"
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"
224 buffer += dedent(f"""\
225 </{xmlns}:catalog>
226 """)
228 return buffer
230 @readonly
231 def Catalogs(self) -> Dict[VLNV, IpxactFile]:
232 return self._catalogs