Coverage for pyEDAA/IPXACT/Component.py: 47%

351 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, Optional as Nullable, ClassVar, Dict, Union 

35 

36from lxml.etree import _Element, QName, _Comment 

37from pyTooling.Decorators import export, readonly 

38from pyTooling.Common import getFullyQualifiedName 

39 

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

41 

42 

43@export 

44class BusInterface(Element): 

45 """Represents an IP-XACT bus interface.""" 

46 

47 def __init__(self, vlnv: VLNV) -> None: 

48 super().__init__(vlnv) 

49 

50 @classmethod 

51 def FromXml(cls, element: _Element) -> "BusInterface": 

52 pass 

53 

54 def ToXml(self, indent=0): 

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

56 

57 return "" 

58 

59 

60@export 

61class IndirectInterface(Element): 

62 """Represents an IP-XACT indirect interface.""" 

63 

64 def __init__(self, vlnv: VLNV) -> None: 

65 super().__init__(vlnv) 

66 

67 def ToXml(self, indent=0): 

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

69 

70 return "" 

71 

72 

73@export 

74class Channel(Element): 

75 """Represents an IP-XACT channel.""" 

76 

77 def __init__(self, vlnv: VLNV) -> None: 

78 super().__init__(vlnv) 

79 

80 def ToXml(self, indent=0): 

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

82 

83 return "" 

84 

85 

86@export 

87class RemapState(Element): 

88 """Represents an IP-XACT remap state.""" 

89 

90 def __init__(self, vlnv: VLNV) -> None: 

91 super().__init__(vlnv) 

92 

93 def ToXml(self, indent=0): 

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

95 

96 return "" 

97 

98 

99@export 

100class AddressSpace(Element): 

101 """Represents an IP-XACT address space.""" 

102 

103 def __init__(self, vlnv: VLNV) -> None: 

104 super().__init__(vlnv) 

105 

106 def ToXml(self, indent=0): 

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

108 

109 return "" 

110 

111 

112@export 

113class MemoryMap(Element): 

114 """Represents an IP-XACT memory map.""" 

115 

116 def __init__(self, vlnv: VLNV) -> None: 

117 super().__init__(vlnv) 

118 

119 def ToXml(self, indent=0): 

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

121 

122 return "" 

123 

124 

125@export 

126class Model(Element): 

127 """Represents an IP-XACT model.""" 

128 

129 def __init__(self, vlnv: VLNV) -> None: 

130 super().__init__(vlnv) 

131 

132 def ToXml(self, indent=0): 

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

134 

135 return "" 

136 

137 

138@export 

139class ComponentGenerator: 

140 """Represents an IP-XACT component generator.""" 

141 

142 def __init__(self, vlnv: VLNV) -> None: 

143 super().__init__(vlnv) 

144 

145 def ToXml(self, indent=0): 

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

147 

148 return "" 

149 

150 

151@export 

152class Choice(Element): 

153 """Represents an IP-XACT choice.""" 

154 

155 def __init__(self, vlnv: VLNV) -> None: 

156 super().__init__(vlnv) 

157 

158 def ToXml(self, indent=0): 

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

160 

161 return "" 

162 

163 

164@export 

165class File(Element): 

166 _path: Path 

167 

168 def __init__(self, path: Path) -> None: 

169 self._path = Path 

170 

171 @readonly 

172 def Path(self) -> Path: 

173 return self._path 

174 

175 @classmethod 

176 def FromXml(cls, fileElement: _Element) -> "FileSet": 

177 fileName = None 

178 fileType = None 

179 for element in fileElement: 

180 if isinstance(element, _Comment): 180 ↛ 181line 180 didn't jump to line 181 because the condition on line 180 was never true

181 continue 

182 

183 elementLocalname = QName(element).localname 

184 if elementLocalname == "name": 

185 fileName = element.text 

186 elif elementLocalname == "fileType": 

187 fileType = element.text 

188 elif elementLocalname == "isStructural": 188 ↛ 191line 188 didn't jump to line 191 because the condition on line 188 was always true

189 pass 

190 else: 

191 raise IPXACTException(f"Unsupported tag '{elementLocalname}' at component → fileSets → fileSet → file.") 

192 

193 return cls(Path(fileName)) 

194 

195 def ToXml(self, indent=0): 

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

197 

198 return "" 

199 

200 def __str__(self) -> str: 

201 return str(self._path) 

202 

203 

204@export 

205class FileSet(Element): 

206 """Represents an IP-XACT fileset.""" 

207 

208 _name: str 

209 _files: List[File] 

210 

211 def __init__(self, name: str, files: List[File]) -> None: 

212 self._name = name 

213 self._files = list(files) 

214 

215 @readonly 

216 def Name(self) -> str: 

217 return self._name 

218 

219 @readonly 

220 def Files(self) -> List[File]: 

221 return self._files 

222 

223 @readonly 

224 def FileCount(self) -> int: 

225 return len(self._files) 

226 

227 @classmethod 

228 def FromXml(cls, fileSetElement: _Element) -> "FileSet": 

229 files = [] 

230 fileSetName = None 

231 for element in fileSetElement: 

232 if isinstance(element, _Comment): 

233 continue 

234 

235 elementLocalname = QName(element).localname 

236 if elementLocalname == "name": 

237 fileSetName = element.text 

238 elif elementLocalname == "file": 238 ↛ 241line 238 didn't jump to line 241 because the condition on line 238 was always true

239 files.append(File.FromXml(element)) 

240 else: 

241 raise IPXACTException(f"Unsupported tag '{elementLocalname}' at component → fileSets → fileSet.") 

242 

243 return cls(fileSetName, files) 

244 

245 def ToXml(self, indent=0): 

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

247 

248 return "" 

249 

250 def __str__(self) -> str: 

251 return f"FileSet {self._name} ({len(self._files)})" 

252 

253 

254@export 

255class WhiteboxElement(Element): 

256 """Represents an IP-XACT whitebos element.""" 

257 

258 def __init__(self, vlnv: VLNV) -> None: 

259 super().__init__(vlnv) 

260 

261 def ToXml(self, indent=0): 

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

263 

264 return "" 

265 

266 

267@export 

268class Cpu(Element): 

269 """Represents an IP-XACT cpu.""" 

270 

271 def __init__(self, vlnv: VLNV) -> None: 

272 super().__init__(vlnv) 

273 

274 def ToXml(self, indent=0): 

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

276 

277 return "" 

278 

279 

280@export 

281class OtherClockDriver(Element): 

282 """Represents an IP-XACT *other* clock driver.""" 

283 

284 def __init__(self, vlnv: VLNV) -> None: 

285 super().__init__(vlnv) 

286 

287 def ToXml(self, indent=0): 

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

289 

290 return "" 

291 

292 

293@export 

294class ResetType(Element): 

295 """Represents an IP-XACT reset type.""" 

296 

297 def __init__(self, vlnv: VLNV) -> None: 

298 super().__init__(vlnv) 

299 

300 def ToXml(self, indent=0): 

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

302 

303 return "" 

304 

305 

306@export 

307class Parameter(Element): 

308 """Represents an IP-XACT parameter.""""""Represents an IP-XACT assertion.""" 

309 

310 def __init__(self, vlnv: VLNV) -> None: 

311 super().__init__(vlnv) 

312 

313 def ToXml(self, indent=0): 

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

315 

316 return "" 

317 

318 

319@export 

320class Assertion(Element): 

321 """Represents an IP-XACT assertion.""" 

322 

323 def __init__(self, vlnv: VLNV) -> None: 

324 super().__init__(vlnv) 

325 

326 def ToXml(self, indent=0): 

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

328 

329 return "" 

330 

331 

332@export 

333class Component(RootElement): 

334 """Represents an IP-XACT components.""" 

335 

336 _ROOT_TAG_NAME: ClassVar[str] = "component" 

337 

338 _busInterfaces: List 

339 _indirectInterfaces: List 

340 _channels: List 

341 _remapStates: List 

342 _addressSpaces: List 

343 _memoryMaps: List 

344 _model: Nullable[Model] 

345 _componentGenerators: List 

346 _choices: List 

347 _fileSets: Dict[str, FileSet] 

348 _whiteboxElements: List 

349 _cpus: List 

350 _otherClockDrivers: List 

351 _resetTypes: List 

352 _parameters: List 

353 _assertions: List 

354 

355 def __init__( 

356 self, 

357 componentFile: Nullable[Path] = None, 

358 parse: bool = False, 

359 vlnv: Nullable[VLNV] = None, 

360 description: Nullable[str] = None 

361 ) -> None: 

362 self._busInterfaces = [] 

363 self._indirectInterfaces = [] 

364 self._channels = [] 

365 self._remapStates = [] 

366 self._addressSpaces = [] 

367 self._memoryMaps = [] 

368 self._model = None 

369 self._componentGenerators = [] 

370 self._choices = [] 

371 self._fileSets = {} 

372 self._whiteboxElements = [] 

373 self._cpus = [] 

374 self._otherClockDrivers = [] 

375 self._resetTypes = [] 

376 self._parameters = [] 

377 self._assertions = [] 

378 

379 super().__init__(componentFile, parse, vlnv, description) 

380 

381 @readonly 

382 def FileSets(self) -> Dict[str, FileSet]: 

383 return self._fileSets 

384 

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

386 elementLocalname = QName(element).localname 

387 if elementLocalname == "busInterfaces": 

388 pass 

389 # for busInterfaceElement in element: 

390 # self.AddItem(BusInterface.FromXml(busInterfaceElement)) 

391 elif elementLocalname == "indirectInterfaces": 

392 pass 

393 elif elementLocalname == "channels": 

394 pass 

395 elif elementLocalname == "remapStates": 

396 pass 

397 elif elementLocalname == "addressSpaces": 

398 pass 

399 elif elementLocalname == "memoryMaps": 

400 pass 

401 elif elementLocalname == "model": 

402 pass 

403 elif elementLocalname == "componentGenerators": 

404 pass 

405 elif elementLocalname == "choices": 

406 pass 

407 elif elementLocalname == "fileSets": 

408 for fileSetElement in element: 

409 if isinstance(fileSetElement, _Comment): 

410 continue 

411 

412 self.AddFileSet(FileSet.FromXml(fileSetElement)) 

413 elif elementLocalname == "whiteboxElements": 

414 pass 

415 elif elementLocalname == "cpus": 

416 pass 

417 elif elementLocalname == "otherClockDrivers": 

418 pass 

419 elif elementLocalname == "resetTypes": 

420 pass 

421 elif elementLocalname == "parameters": 

422 pass 

423 elif elementLocalname == "assertions": 423 ↛ 426line 423 didn't jump to line 426 because the condition on line 423 was always true

424 pass 

425 else: 

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

427 

428 def SetItem(self, item): 

429 if isinstance(item, Model): 

430 self._model = item 

431 else: 

432 raise ValueError() 

433 

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

435 if isinstance(item, BusInterface): 

436 self._busInterfaces.append(item) 

437 elif isinstance(item, IndirectInterface): 

438 self._indirectInterfaces.append(item) 

439 elif isinstance(item, Channel): 

440 self._channels.append(item) 

441 elif isinstance(item, RemapState): 

442 self._remapStates.append(item) 

443 elif isinstance(item, AddressSpace): 

444 self._addressSpaces.append(item) 

445 elif isinstance(item, MemoryMap): 

446 self._memoryMaps.append(item) 

447 elif isinstance(item, ComponentGenerator): 

448 self._componentGenerators.append(item) 

449 elif isinstance(item, Choice): 

450 self._choices.append(item) 

451 elif isinstance(item, FileSet): 

452 self.AddFileSet(item) 

453 elif isinstance(item, WhiteboxElement): 

454 self._whiteboxElements.append(item) 

455 elif isinstance(item, Cpu): 

456 self._cpus.append(item) 

457 elif isinstance(item, OtherClockDriver): 

458 self._otherClockDrivers.append(item) 

459 elif isinstance(item, ResetType): 

460 self._resetTypes.append(item) 

461 elif isinstance(item, Parameter): 

462 self._parameters.append(item) 

463 elif isinstance(item, Assertion): 

464 self._assertions.append(item) 

465 else: 

466 ex = TypeError("Parameter 'item' is not a BusInterface, IndirectInterface, Channel, RemapState, AddressSpace, MemoryMap, ComponentGenerator, Choice, FileSet, WhiteboxElement, Cpu, OtherClockDriver, ResetType, Parameter, or Assertion.") 

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

468 raise ex 

469 

470 def AddFileSet(self, fileset: FileSet): 

471 if not isinstance(fileset, FileSet): 471 ↛ 472line 471 didn't jump to line 472 because the condition on line 471 was never true

472 ex = TypeError("Parameter 'fileset' is not a FileSet.") 

473 ex.add_note(f"Got type '{getFullyQualifiedName(fileset)}'.") 

474 raise ex 

475 

476 if fileset._name in self._fileSets: 476 ↛ 477line 476 didn't jump to line 477 because the condition on line 476 was never true

477 raise ValueError(f"Duplicate fileset '{fileset._name}'.") 

478 

479 self._fileSets[fileset._name] = fileset 

480 

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

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

483 

484 xmlns = schema.NamespacePrefix 

485 buffer = dedent(f"""\ 

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

487 <{xmlns}:component 

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

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

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

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

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

493 """) 

494 

495 if self._busInterfaces: 

496 buffer += f"\t<{xmlns}:busInterfaces>\n" 

497 for busInterface in self._busInterfaces: 

498 buffer += busInterface.ToXml(2, schema) 

499 buffer += f"\t</{xmlns}:busInterfaces>\n" 

500 

501 if self._indirectInterfaces: 

502 buffer += f"\t<{xmlns}:indirectInterfaces>\n" 

503 for indirectInterface in self._indirectInterfaces: 

504 buffer += indirectInterface.ToXml(2, schema) 

505 buffer += f"\t</{xmlns}:indirectInterfaces>\n" 

506 

507 if self._channels: 

508 buffer += f"\t<{xmlns}:channels>\n" 

509 for channel in self._channels: 

510 buffer += channel.ToXml(2, schema) 

511 buffer += f"\t</{xmlns}:channels>\n" 

512 

513 if self._remapStates: 

514 buffer += f"\t<{xmlns}:remapStates>\n" 

515 for remapState in self._remapStates: 

516 buffer += remapState.ToXml(2, schema) 

517 buffer += f"\t</{xmlns}:remapStates>\n" 

518 

519 if self._addressSpaces: 

520 buffer += f"\t<{xmlns}:addressSpaces>\n" 

521 for addressSpace in self._addressSpaces: 

522 buffer += addressSpace.ToXml(2, schema) 

523 buffer += f"\t</{xmlns}:addressSpaces>\n" 

524 

525 if self._memoryMaps: 

526 buffer += f"\t<{xmlns}:memoryMaps>\n" 

527 for memoryMap in self._memoryMaps: 

528 buffer += memoryMap.ToXml(2, schema) 

529 buffer += f"\t</{xmlns}:memoryMaps>\n" 

530 

531 if self._model: 

532 buffer += f"\t<{xmlns}:model>\n" 

533 buffer += self._model.ToXml(2, schema) 

534 buffer += f"\t</{xmlns}:model>\n" 

535 

536 if self._componentGenerators: 

537 buffer += f"\t<{xmlns}:componentGenerators>\n" 

538 for componentGenerator in self._componentGenerators: 

539 buffer += componentGenerator.ToXml(2, schema) 

540 buffer += f"\t</{xmlns}:componentGenerators>\n" 

541 

542 if self._choices: 

543 buffer += f"\t<{xmlns}:choices>\n" 

544 for choice in self._choices: 

545 buffer += choice.ToXml(2, schema) 

546 buffer += f"\t</{xmlns}:choices>\n" 

547 

548 if self._fileSets: 

549 buffer += f"\t<{xmlns}:fileSets>\n" 

550 for fileSet in self._fileSets: 

551 buffer += fileSet.ToXml(2, schema) 

552 buffer += f"\t</{xmlns}:fileSets>\n" 

553 

554 if self._whiteboxElements: 

555 buffer += f"\t<{xmlns}:whiteboxElements>\n" 

556 for whiteboxElement in self._whiteboxElements: 

557 buffer += whiteboxElement.ToXml(2, schema) 

558 buffer += f"\t</{xmlns}:whiteboxElements>\n" 

559 

560 if self._cpus: 

561 buffer += f"\t<{xmlns}:cpus>\n" 

562 for cpu in self._cpus: 

563 buffer += cpu.ToXml(2, schema) 

564 buffer += f"\t</{xmlns}:cpus>\n" 

565 

566 if self._otherClockDrivers: 

567 buffer += f"\t<{xmlns}:otherClockDrivers>\n" 

568 for otherClockDriver in self._otherClockDrivers: 

569 buffer += otherClockDriver.ToXml(2, schema) 

570 buffer += f"\t</{xmlns}:otherClockDrivers>\n" 

571 

572 if self._resetTypes: 

573 buffer += f"\t<{xmlns}:resetTypes>\n" 

574 for resetType in self._resetTypes: 

575 buffer += resetType.ToXml(2, schema) 

576 buffer += f"\t</{xmlns}:resetTypes>\n" 

577 

578 if self._parameters: 

579 buffer += f"\t<{xmlns}:parameters>\n" 

580 for parameter in self._parameters: 

581 buffer += parameter.ToXml(2, schema) 

582 buffer += f"\t</{xmlns}:parameters>\n" 

583 

584 if self._assertions: 

585 buffer += f"\t<{xmlns}:assertions>\n" 

586 for assertion in self._assertions: 

587 buffer += assertion.ToXml(2, schema) 

588 buffer += f"\t</{xmlns}:assertions>\n" 

589 

590 buffer += dedent(f"""\ 

591 </{xmlns}:component> 

592 """) 

593 

594 return buffer