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
« 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
36from lxml.etree import QName, _Element
38from pyTooling.Decorators import export, readonly
39from pyTooling.Common import getFullyQualifiedName
41from pyEDAA.IPXACT import NamedElement, RootElement, VLNV, IPXACTException, __DEFAULT_SCHEMA__, IPXACTSchema, Element
42from pyEDAA.IPXACT.Component import Component
45@export
46class IpxactFile(NamedElement):
47 """Represents a IP-XACT file."""
49 _name: str #: Name
50 _description: str #: Description
52 def __init__(self, vlnv: VLNV, name: str, description: str) -> None:
53 """
54 Instantiates an ipxactFile structure.
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)
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.")
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.")
81 self._vlnv = vlnv
82 self._name = name
83 self._description = description
85 @classmethod
86 def FromXml(cls, ipxactFileElement):
87 """Constructs an instance of ``IpxactFile`` from an lxml element."""
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'.")
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")
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'.")
112 ipxactFile = cls(vlnv, name, description)
113 return ipxactFile
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 """)
131@export
132class Catalog(RootElement):
133 """Represents an IP-XACT catalog."""
135 _ROOT_TAG_NAME: ClassVar[str] = "catalog"
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
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 = []
162 super().__init__(catalogFile, parse, vlnv, description)
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.")
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
194 def ToXml(self, schema: IPXACTSchema = __DEFAULT_SCHEMA__) -> str:
195 """Converts the object's data into XML format."""
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 """)
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"
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"
220 buffer += dedent(f"""\
221 </{xmlns}:catalog>
222 """)
224 return buffer
226 @readonly
227 def Catalogs(self) -> Dict[VLNV, IpxactFile]:
228 return self._catalogs