Coverage for pyEDAA/OSVVM/Project/__init__.py: 91%

470 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-27 22:24 +0000

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

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

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

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | \___ \\ \ / / \ \ / /| |\/| | # 

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

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

7# |_| |___/ # 

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2025-2025 Patrick Lehmann - Boetzingen, Germany # 

15# # 

16# Licensed under the Apache License, Version 2.0 (the "License"); # 

17# you may not use this file except in compliance with the License. # 

18# You may obtain a copy of the License at # 

19# # 

20# http://www.apache.org/licenses/LICENSE-2.0 # 

21# # 

22# Unless required by applicable law or agreed to in writing, software # 

23# distributed under the License is distributed on an "AS IS" BASIS, # 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

25# See the License for the specific language governing permissions and # 

26# limitations under the License. # 

27# # 

28# SPDX-License-Identifier: Apache-2.0 # 

29# ==================================================================================================================== # 

30# 

31from pathlib import Path 

32from typing import Optional as Nullable, List, Dict, Mapping, Iterable, TypeVar, Generic, Generator 

33 

34from pyTooling.Common import getFullyQualifiedName 

35from pyTooling.Decorators import readonly, export 

36from pyTooling.MetaClasses import ExtendedType 

37from pyVHDLModel import VHDLVersion 

38 

39from pyEDAA.OSVVM import OSVVMException 

40 

41 

42__all__ = ["osvvmContext"] 

43 

44 

45_ParentType = TypeVar("_ParentType", bound="Base") 

46 

47 

48@export 

49class Base(Generic[_ParentType], metaclass=ExtendedType, slots=True): 

50 _parent: Nullable[_ParentType] 

51 

52 def __init__(self, parent: Nullable[_ParentType] = None): 

53 self._parent = parent 

54 

55 @readonly 

56 def Parent(self) -> _ParentType: 

57 return self._parent 

58 

59 

60@export 

61class Named(Base[_ParentType], Generic[_ParentType]): 

62 _name: str 

63 

64 def __init__( 

65 self, 

66 name: str, 

67 parent: Nullable[_ParentType] = None 

68 ) -> None: 

69 super().__init__(parent) 

70 

71 if not isinstance(name, str): # pragma: no cover 

72 ex = TypeError(f"Parameter 'name' is not a string.") 

73 ex.add_note(f"Got type '{getFullyQualifiedName(name)}'.") 

74 raise ex 

75 

76 self._name = name 

77 

78 @readonly 

79 def Name(self) -> str: 

80 return self._name 

81 

82 def __repr__(self) -> str: 

83 return f"{self.__class__.__name__}: {self._name}" 

84 

85 

86@export 

87class Option(metaclass=ExtendedType, slots=True): 

88 pass 

89 

90 

91@export 

92class NoNullRangeWarning(Option): 

93 def __init__(self) -> None: 

94 super().__init__() 

95 

96 def __repr__(self) -> str: 

97 return "NoNullRangeWarning" 

98 

99 

100@export 

101class SourceFile(Base[_ParentType], Generic[_ParentType]): 

102 """A base-class describing any source file (VHDL, Verilog, ...) supported by OSVVM Scripts.""" 

103 

104 _path: Path 

105 

106 def __init__( 

107 self, 

108 path: Path, 

109 parent: Nullable[Base] = None 

110 ) -> None: 

111 super().__init__(parent) 

112 

113 if not isinstance(path, Path): # pragma: no cover 

114 ex = TypeError(f"Parameter 'path' is not a Path.") 

115 ex.add_note(f"Got type '{getFullyQualifiedName(path)}'.") 

116 raise ex 

117 

118 self._path = path 

119 

120 @readonly 

121 def Path(self) -> Path: 

122 """ 

123 Read-only property to access the path to the sourcefile. 

124 

125 :returns: The sourcefile's path. 

126 """ 

127 return self._path 

128 

129 def __repr__(self) -> str: 

130 return f"SourceFile: {self._path}" 

131 

132 

133@export 

134class VHDLSourceFile(SourceFile["VHDLLibrary"]): 

135 _vhdlVersion: VHDLVersion 

136 _noNullRangeWarning: Nullable[bool] 

137 

138 def __init__( 

139 self, 

140 path: Path, 

141 vhdlVersion: VHDLVersion = VHDLVersion.VHDL2008, 

142 vhdlLibrary: Nullable["VHDLLibrary"] = None, 

143 noNullRangeWarning: Nullable[bool] = None 

144 ): 

145 if vhdlLibrary is None: 

146 super().__init__(path, None) 

147 elif isinstance(vhdlLibrary, VHDLLibrary): 

148 super().__init__(path, vhdlLibrary) 

149 vhdlLibrary._files.append(self) 

150 else: # pragma: no cover 

151 ex = TypeError(f"Parameter 'vhdlLibrary' is not a Library.") 

152 ex.add_note(f"Got type '{getFullyQualifiedName(vhdlLibrary)}'.") 

153 raise ex 

154 

155 if not isinstance(vhdlVersion, VHDLVersion): # pragma: no cover 

156 ex = TypeError(f"Parameter 'vhdlVersion' is not a VHDLVersion.") 

157 ex.add_note(f"Got type '{getFullyQualifiedName(vhdlVersion)}'.") 

158 raise ex 

159 

160 self._vhdlVersion = vhdlVersion 

161 

162 if noNullRangeWarning is not None and not isinstance(noNullRangeWarning, bool): 162 ↛ 163line 162 didn't jump to line 163 because the condition on line 162 was never true

163 ex = TypeError(f"Parameter 'noNullRangeWarning' is not a boolean.") 

164 ex.add_note(f"Got type '{getFullyQualifiedName(noNullRangeWarning)}'.") 

165 raise ex 

166 

167 self._noNullRangeWarning = noNullRangeWarning 

168 

169 @readonly 

170 def VHDLLibrary(self) -> Nullable["VHDLLibrary"]: 

171 return self._parent 

172 

173 @property 

174 def VHDLVersion(self) -> VHDLVersion: 

175 return self._vhdlVersion 

176 

177 @VHDLVersion.setter 

178 def VHDLVersion(self, value: VHDLVersion) -> None: 

179 if not isinstance(value, VHDLVersion): 179 ↛ 180line 179 didn't jump to line 180 because the condition on line 179 was never true

180 ex = TypeError(f"Parameter 'value' is not a VHDLVersion.") 

181 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

182 raise ex 

183 

184 self._vhdlVersion = value 

185 

186 @property 

187 def NoNullRangeWarning(self) -> bool: 

188 return self._noNullRangeWarning 

189 

190 @NoNullRangeWarning.setter 

191 def NoNullRangeWarning(self, value: bool) -> None: 

192 if value is not None and not isinstance(value, bool): 

193 ex = TypeError(f"Parameter 'value' is not a boolean.") 

194 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

195 raise ex 

196 

197 self._noNullRangeWarning = value 

198 

199 def __repr__(self) -> str: 

200 options = "" 

201 if self._noNullRangeWarning is not None: 201 ↛ 202line 201 didn't jump to line 202 because the condition on line 201 was never true

202 options += f", NoNullRangeWarning" 

203 return f"VHDLSourceFile: {self._path} ({self._vhdlVersion}{options})" 

204 

205@export 

206class VHDLLibrary(Named["Build"]): 

207 """A VHDL library collecting multiple VHDL files containing VHDL design units.""" 

208 

209 _files: List[VHDLSourceFile] 

210 

211 def __init__( 

212 self, 

213 name: str, 

214 vhdlFiles: Nullable[Iterable[VHDLSourceFile]] = None, 

215 build: Nullable["Build"] = None 

216 ) -> None: 

217 if build is None: 

218 super().__init__(name, None) 

219 elif isinstance(build, Build): 

220 super().__init__(name, build) 

221 build._vhdlLibraries[name] = self 

222 else: # pragma: no cover 

223 ex = TypeError(f"Parameter 'build' is not a Build.") 

224 ex.add_note(f"Got type '{getFullyQualifiedName(build)}'.") 

225 raise ex 

226 

227 self._files = [] 

228 if vhdlFiles is None: 

229 pass 

230 elif isinstance(vhdlFiles, Iterable): 

231 for vhdlFile in vhdlFiles: 

232 vhdlFile._parent = self 

233 self._files.append(vhdlFile) 

234 else: # pragma: no cover 

235 ex = TypeError(f"Parameter 'vhdlFiles' is not an iterable of VHDLSourceFile.") 

236 ex.add_note(f"Got type '{getFullyQualifiedName(vhdlFiles)}'.") 

237 raise ex 

238 

239 @readonly 

240 def Build(self) -> Nullable["Build"]: 

241 return self._parent 

242 

243 @readonly 

244 def Files(self) -> List[SourceFile]: 

245 return self._files 

246 

247 def AddFile(self, file: VHDLSourceFile) -> None: 

248 if not isinstance(file, VHDLSourceFile): # pragma: no cover 

249 ex = TypeError(f"Parameter 'file' is not a VHDLSourceFile.") 

250 ex.add_note(f"Got type '{getFullyQualifiedName(file)}'.") 

251 raise ex 

252 

253 file._parent = self 

254 self._files.append(file) 

255 

256 def __repr__(self) -> str: 

257 return f"VHDLLibrary: {self._name}" 

258 

259 

260@export 

261class GenericValue(Option): 

262 _name: str 

263 _value: str 

264 

265 def __init__( 

266 self, 

267 name: str, 

268 value: str 

269 ) -> None: 

270 super().__init__() 

271 

272 if not isinstance(name, str): # pragma: no cover 

273 ex = TypeError(f"Parameter 'name' is not a string.") 

274 ex.add_note(f"Got type '{getFullyQualifiedName(name)}'.") 

275 raise ex 

276 

277 self._name = name 

278 

279 if not isinstance(value, str): # pragma: no cover 

280 ex = TypeError(f"Parameter 'value' is not a string.") 

281 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

282 raise ex 

283 

284 self._value = value 

285 

286 @readonly 

287 def Name(self) -> str: 

288 return self._name 

289 

290 @readonly 

291 def Value(self) -> str: 

292 return self._value 

293 

294 def __repr__(self) -> str: 

295 return f"{self._name} = {self._value}" 

296 

297 

298@export 

299class Testcase(Named["Testsuite"]): 

300 _toplevelName: Nullable[str] 

301 _generics: Dict[str, str] 

302 

303 def __init__( 

304 self, 

305 name: str, 

306 toplevelName: Nullable[str] = None, 

307 generics: Nullable[Iterable[GenericValue] | Mapping[str, str]] = None, 

308 testsuite: Nullable["Testsuite"] = None 

309 ) -> None: 

310 if testsuite is None: 

311 super().__init__(name, None) 

312 elif isinstance(testsuite, Testsuite): 

313 super().__init__(name, testsuite) 

314 testsuite._testcases[name] = self 

315 else: # pragma: no cover 

316 ex = TypeError(f"Parameter 'testsuite' is not a Testsuite.") 

317 ex.add_note(f"Got type '{getFullyQualifiedName(testsuite)}'.") 

318 raise ex 

319 

320 if not (toplevelName is None or isinstance(toplevelName, str)): # pragma: no cover 

321 ex = TypeError(f"Parameter 'toplevelName' is not a string.") 

322 ex.add_note(f"Got type '{getFullyQualifiedName(toplevelName)}'.") 

323 raise ex 

324 

325 self._toplevelName = toplevelName 

326 

327 self._generics = {} 

328 if generics is None: 

329 pass 

330 elif isinstance(generics, Mapping): 

331 for key, value in generics.items(): 

332 self._generics[key] = value 

333 elif isinstance(generics, Iterable): 

334 for item in generics: 

335 self._generics[item._name] = item._value 

336 else: # pragma: no cover 

337 ex = TypeError(f"Parameter 'generics' is not an iterable of GenericValue nor a dictionary of strings.") 

338 ex.add_note(f"Got type '{getFullyQualifiedName(generics)}'.") 

339 raise ex 

340 

341 @readonly 

342 def Testsuite(self) -> "Testsuite": 

343 return self._parent 

344 

345 @readonly 

346 def ToplevelName(self) -> str: 

347 return self._toplevelName 

348 

349 @readonly 

350 def Generics(self) -> Dict[str, str]: 

351 return self._generics 

352 

353 def SetToplevel(self, toplevelName: str) -> None: 

354 if not isinstance(toplevelName, str): # pragma: no cover 

355 ex = TypeError(f"Parameter 'toplevelName' is not a string.") 

356 ex.add_note(f"Got type '{getFullyQualifiedName(toplevelName)}'.") 

357 raise ex 

358 

359 self._toplevelName = toplevelName 

360 

361 def AddGeneric(self, genericValue: GenericValue): 

362 if not isinstance(genericValue, GenericValue): # pragma: no cover 

363 ex = TypeError(f"Parameter 'genericValue' is not a GenericValue.") 

364 ex.add_note(f"Got type '{getFullyQualifiedName(genericValue)}'.") 

365 raise ex 

366 

367 self._generics[genericValue._name] = genericValue._value 

368 

369 def __repr__(self) -> str: 

370 generics = f" - [{', '.join([f'{n}={v}' for n,v in self._generics.items()])}]" if len(self._generics) > 0 else "" 

371 return f"Testcase: {self._name}{generics}" 

372 

373 

374@export 

375class Testsuite(Named["Build"]): 

376 _testcases: Dict[str, Testcase] 

377 

378 def __init__( 

379 self, 

380 name: str, 

381 testcases: Nullable[Iterable[Testcase] | Mapping[str, Testcase]] = None, 

382 build: Nullable["Build"] = None 

383 ) -> None: 

384 if build is None: 

385 super().__init__(name, None) 

386 elif isinstance(build, Build): 

387 super().__init__(name, build) 

388 build._testsuites[name] = self 

389 else: # pragma: no cover 

390 ex = TypeError(f"Parameter 'build' is not a Build.") 

391 ex.add_note(f"Got type '{getFullyQualifiedName(build)}'.") 

392 raise ex 

393 

394 self._testcases = {} 

395 if testcases is None: 

396 pass 

397 elif isinstance(testcases, Mapping): 

398 for key, value in testcases.items(): 

399 value._parent = self 

400 self._testcases[key] = value 

401 elif isinstance(testcases, Iterable): 

402 for item in testcases: 

403 item._parent = self 

404 self._testcases[item._name] = item 

405 else: # pragma: no cover 

406 ex = TypeError(f"Parameter 'testcases' is not an iterable of Testcase nor a mapping of Testcase.") 

407 ex.add_note(f"Got type '{getFullyQualifiedName(testcases)}'.") 

408 raise ex 

409 

410 @readonly 

411 def Build(self) -> Nullable["Build"]: 

412 return self._parent 

413 

414 @readonly 

415 def Testcases(self) -> Dict[str, Testcase]: 

416 return self._testcases 

417 

418 def AddTestcase(self, testcase: Testcase) -> None: 

419 if not isinstance(testcase, Testcase): # pragma: no cover 

420 ex = TypeError(f"Parameter 'testcase' is not a Testcase.") 

421 ex.add_note(f"Got type '{getFullyQualifiedName(testcase)}'.") 

422 raise ex 

423 

424 testcase._parent = self 

425 self._testcases[testcase._name] = testcase 

426 

427 def __repr__(self) -> str: 

428 return f"Testsuite: {self._name}" 

429 

430 

431@export 

432class BuildName(Option): 

433 _name: str 

434 

435 def __init__( 

436 self, 

437 name: str, 

438 ) -> None: 

439 super().__init__() 

440 

441 if not isinstance(name, str): # pragma: no cover 

442 ex = TypeError(f"Parameter 'name' is not a string.") 

443 ex.add_note(f"Got type '{getFullyQualifiedName(name)}'.") 

444 raise ex 

445 

446 self._name = name 

447 

448 @readonly 

449 def Name(self) -> str: 

450 return self._name 

451 

452 def __repr__(self) -> str: 

453 return f"BuildName: {self._name}" 

454 

455 

456@export 

457class Build(Named["Project"]): 

458 _includedFiles: List[Path] 

459 _vhdlLibraries: Dict[str, VHDLLibrary] 

460 _testsuites: Dict[str, Testsuite] 

461 

462 def __init__( 

463 self, 

464 name: str, 

465 vhdlLibraries: Nullable[Iterable[VHDLLibrary] | Mapping[str, VHDLLibrary]] = None, 

466 testsuites: Nullable[Iterable[Testsuite] | Mapping[str, Testsuite]] = None, 

467 project: Nullable[Base] = None 

468 ) -> None: 

469 if project is None: 

470 super().__init__(name, None) 

471 elif isinstance(project, Project): 

472 super().__init__(name, project) 

473 project._builds[name] = self 

474 else: # pragma: no cover 

475 ex = TypeError(f"Parameter 'project' is not a Project.") 

476 ex.add_note(f"Got type '{getFullyQualifiedName(project)}'.") 

477 raise ex 

478 

479 self._includedFiles = [] 

480 self._vhdlLibraries = {} 

481 if vhdlLibraries is None: 

482 pass 

483 elif isinstance(vhdlLibraries, Mapping): 

484 for key, value in vhdlLibraries.items(): 

485 value._parent = self 

486 self._vhdlLibraries[key] = value 

487 elif isinstance(vhdlLibraries, Iterable): 

488 for item in vhdlLibraries: 

489 item._parent = self 

490 self._vhdlLibraries[item._name] = item 

491 else: # pragma: no cover 

492 ex = TypeError(f"Parameter 'libraries' is not an iterable of VHDLLibrary nor a mapping of VHDLLibrary.") 

493 ex.add_note(f"Got type '{getFullyQualifiedName(vhdlLibraries)}'.") 

494 raise ex 

495 

496 self._testsuites = {} 

497 if testsuites is None: 

498 pass 

499 elif isinstance(testsuites, Mapping): 

500 for key, value in testsuites.items(): 

501 value._parent = self 

502 self._testsuites[key] = value 

503 elif isinstance(testsuites, Iterable): 

504 for item in testsuites: 

505 item._parent = self 

506 self._testsuites[item._name] = item 

507 else: # pragma: no cover 

508 ex = TypeError(f"Parameter 'testsuites' is not an iterable of Testsuite nor a mapping of Testsuite.") 

509 ex.add_note(f"Got type '{getFullyQualifiedName(testsuites)}'.") 

510 raise ex 

511 

512 @readonly 

513 def Project(self) -> Nullable["Project"]: 

514 return self._parent 

515 

516 @readonly 

517 def IncludedFiles(self) -> Generator[Path, None, None]: 

518 return (file for file in self._includedFiles) 

519 

520 @readonly 

521 def VHDLLibraries(self) -> Dict[str, VHDLLibrary]: 

522 return self._vhdlLibraries 

523 

524 @readonly 

525 def Testsuites(self) -> Dict[str, Testsuite]: 

526 return self._testsuites 

527 

528 def AddVHDLLibrary(self, vhdlLibrary: VHDLLibrary) -> None: 

529 if not isinstance(vhdlLibrary, VHDLLibrary): # pragma: no cover 

530 ex = TypeError(f"Parameter 'vhdlLibrary' is not a VHDLLibrary.") 

531 ex.add_note(f"Got type '{getFullyQualifiedName(vhdlLibrary)}'.") 

532 raise ex 

533 

534 vhdlLibrary._parent = self 

535 self._vhdlLibraries[vhdlLibrary._name] = vhdlLibrary 

536 

537 def AddTestsuite(self, testsuite: Testsuite) -> None: 

538 if not isinstance(testsuite, Testsuite): # pragma: no cover 

539 ex = TypeError(f"Parameter 'testsuite' is not a Testsuite.") 

540 ex.add_note(f"Got type '{getFullyQualifiedName(testsuite)}'.") 

541 raise ex 

542 

543 testsuite._parent = self 

544 self._testsuites[testsuite._name] = testsuite 

545 

546 def __repr__(self) -> str: 

547 return f"Build: {self._name}" 

548 

549 

550@export 

551class Project(Named[None]): 

552 _builds: Dict[str, Build] 

553 

554 def __init__( 

555 self, 

556 name: str, 

557 builds: Nullable[Iterable[Build] | Mapping[str, Build]] = None 

558 ) -> None: 

559 super().__init__(name, None) 

560 

561 self._builds = {} 

562 if builds is None: 

563 pass 

564 elif isinstance(builds, Mapping): 

565 for key, value in builds.items(): 

566 value._parent = self 

567 self._builds[key] = value 

568 elif isinstance(builds, Iterable): 

569 for item in builds: 

570 item._parent = self 

571 self._builds[item._name] = item 

572 else: # pragma: no cover 

573 ex = TypeError(f"Parameter 'builds' is not an iterable of Build nor a mapping of Build.") 

574 ex.add_note(f"Got type '{getFullyQualifiedName(builds)}'.") 

575 raise ex 

576 

577 @readonly 

578 def Builds(self) -> Dict[str, Build]: 

579 return self._builds 

580 

581 @readonly 

582 def IncludedFiles(self) -> Generator[Path, None, None]: 

583 for build in self._builds.values(): 

584 yield from build.IncludedFiles 

585 

586 def AddBuild(self, build: Build) -> None: 

587 if not isinstance(build, Build): # pragma: no cover 

588 ex = TypeError(f"Parameter 'build' is not a Build.") 

589 ex.add_note(f"Got type '{getFullyQualifiedName(build)}'.") 

590 raise ex 

591 

592 build._parent = self 

593 self._builds[build._name] = build 

594 

595 def __repr__(self) -> str: 

596 return f"Project: {self._name}" 

597 

598@export 

599class Context(Base): 

600 # _tcl: TclEnvironment 

601 

602 _processor: "OsvvmProFileProcessor" 

603 _lastException: Exception 

604 

605 _workingDirectory: Path 

606 _currentDirectory: Path 

607 _includedFiles: List[Path] 

608 

609 _vhdlversion: VHDLVersion 

610 

611 _vhdlLibraries: Dict[str, VHDLLibrary] 

612 _vhdlLibrary: Nullable[VHDLLibrary] 

613 

614 _testsuites: Dict[str, Testsuite] 

615 _testsuite: Nullable[Testsuite] 

616 _testcase: Nullable[Testcase] 

617 _options: Dict[int, Option] 

618 

619 _builds: Dict[str, Build] 

620 _build: Nullable[Build] 

621 

622 def __init__(self) -> None: 

623 super().__init__() 

624 

625 self._processor = None 

626 self._lastException = None 

627 

628 self._workingDirectory = Path.cwd() 

629 self._currentDirectory = self._workingDirectory 

630 self._includedFiles = [] 

631 

632 self._vhdlversion = VHDLVersion.VHDL2008 

633 

634 self._vhdlLibrary = None 

635 self._vhdlLibraries = {} 

636 

637 self._testcase = None 

638 self._testsuite = None 

639 self._testsuites = {} 

640 self._options = {} 

641 

642 self._build = None 

643 self._builds = {} 

644 

645 def Clear(self) -> None: 

646 self._processor = None 

647 self._lastException = None 

648 

649 self._workingDirectory = Path.cwd() 

650 self._currentDirectory = self._workingDirectory 

651 self._includedFiles = [] 

652 

653 self._vhdlversion = VHDLVersion.VHDL2008 

654 

655 self._vhdlLibrary = None 

656 self._vhdlLibraries = {} 

657 

658 self._testcase = None 

659 self._testsuite = None 

660 self._testsuites = {} 

661 self._options = {} 

662 

663 self._build = None 

664 self._builds = {} 

665 

666 @readonly 

667 def Processor(self): # -> "Tk": 

668 return self._processor 

669 

670 @property 

671 def LastException(self) -> Exception: 

672 lastException = self._lastException 

673 self._lastException = None 

674 return lastException 

675 

676 @LastException.setter 

677 def LastException(self, value: Exception) -> None: 

678 self._lastException = value 

679 

680 @readonly 

681 def WorkingDirectory(self) -> Path: 

682 return self._workingDirectory 

683 

684 @readonly 

685 def CurrentDirectory(self) -> Path: 

686 return self._currentDirectory 

687 

688 @property 

689 def VHDLVersion(self) -> VHDLVersion: 

690 return self._vhdlversion 

691 

692 @VHDLVersion.setter 

693 def VHDLVersion(self, value: VHDLVersion) -> None: 

694 self._vhdlversion = value 

695 

696 @readonly 

697 def IncludedFiles(self) -> List[Path]: 

698 return self._includedFiles 

699 

700 @readonly 

701 def VHDLLibraries(self) -> Dict[str, VHDLLibrary]: 

702 return self._vhdlLibraries 

703 

704 @readonly 

705 def VHDLLibrary(self) -> VHDLLibrary: 

706 return self._vhdlLibrary 

707 

708 @readonly 

709 def Testsuites(self) -> Dict[str, Testsuite]: 

710 return self._testsuites 

711 

712 @readonly 

713 def Testsuite(self) -> Testsuite: 

714 return self._testsuite 

715 

716 @readonly 

717 def TestCase(self) -> Testcase: 

718 return self._testcase 

719 

720 @readonly 

721 def Build(self) -> Build: 

722 return self._build 

723 

724 @readonly 

725 def Builds(self) -> Dict[str, Build]: 

726 return self._builds 

727 

728 def ToProject(self, projectName: str) -> Project: 

729 project = Project(projectName, self._builds) 

730 

731 return project 

732 

733 def BeginBuild(self, buildName: str) -> Build: 

734 if len(self._vhdlLibraries) > 0: 734 ↛ 735line 734 didn't jump to line 735 because the condition on line 734 was never true

735 raise OSVVMException(f"VHDL libraries have been created outside of an OSVVM build script.") 

736 if len(self._testsuites) > 0: 736 ↛ 737line 736 didn't jump to line 737 because the condition on line 736 was never true

737 raise OSVVMException(f"Testsuites have been created outside of an OSVVM build script.") 

738 

739 build = Build(buildName) 

740 build._vhdlLibraries = self._vhdlLibraries 

741 build._testsuites = self._testsuites 

742 

743 self._build = build 

744 self._builds[buildName] = build 

745 

746 return build 

747 

748 def EndBuild(self) -> Build: 

749 build = self._build 

750 

751 self._vhdlLibrary = None 

752 self._vhdlLibraries = {} 

753 self._testcase = None 

754 self._testsuite = None 

755 self._testsuites = {} 

756 self._build = None 

757 

758 return build 

759 

760 def IncludeFile(self, proFileOrBuildDirectory: Path) -> Path: 

761 if not isinstance(proFileOrBuildDirectory, Path): # pragma: no cover 

762 ex = TypeError(f"Parameter 'proFileOrBuildDirectory' is not a Path.") 

763 ex.add_note(f"Got type '{getFullyQualifiedName(proFileOrBuildDirectory)}'.") 

764 self._lastException = ex 

765 raise ex 

766 

767 if proFileOrBuildDirectory.is_absolute(): 767 ↛ 768line 767 didn't jump to line 768 because the condition on line 767 was never true

768 ex = OSVVMException(f"Absolute path '{proFileOrBuildDirectory}' not supported.") 

769 self._lastException = ex 

770 raise ex 

771 

772 path = (self._currentDirectory / proFileOrBuildDirectory).resolve() 

773 if path.is_file(): 

774 if path.suffix == ".pro": 774 ↛ 778line 774 didn't jump to line 778 because the condition on line 774 was always true

775 self._currentDirectory = path.parent.relative_to(self._workingDirectory, walk_up=True) 

776 proFile = self._currentDirectory / path.name 

777 else: 

778 ex = OSVVMException(f"Path '{proFileOrBuildDirectory}' is not a *.pro file.") 

779 self._lastException = ex 

780 raise ex 

781 elif path.is_dir(): 

782 self._currentDirectory = path 

783 proFile = path / "build.pro" 

784 if not proFile.exists(): 

785 proFile = path / f"{path.name}.pro" 

786 if not proFile.exists(): # pragma: no cover 

787 ex = OSVVMException(f"Path '{proFileOrBuildDirectory}' is not a build directory.") 

788 ex.__cause__ = FileNotFoundError(path / "build.pro") 

789 self._lastException = ex 

790 raise ex 

791 else: # pragma: no cover 

792 ex = OSVVMException(f"Path '{proFileOrBuildDirectory}' is not a *.pro file or build directory.") 

793 self._lastException = ex 

794 raise ex 

795 

796 self._includedFiles.append(proFile) 

797 return proFile 

798 

799 def EvaluateFile(self, proFile: Path) -> None: 

800 self._processor.EvaluateProFile(proFile) 

801 

802 def SetLibrary(self, name: str): 

803 try: 

804 self._vhdlLibrary = self._vhdlLibraries[name] 

805 except KeyError: 

806 self._vhdlLibrary = VHDLLibrary(name, build=self._build) 

807 self._vhdlLibraries[name] = self._vhdlLibrary 

808 

809 def AddVHDLFile(self, vhdlFile: VHDLSourceFile) -> None: 

810 if self._vhdlLibrary is None: 

811 self.SetLibrary("default") 

812 

813 vhdlFile.VHDLVersion = self._vhdlversion 

814 self._vhdlLibrary.AddFile(vhdlFile) 

815 

816 def SetTestsuite(self, testsuiteName: str): 

817 try: 

818 self._testsuite = self._testsuites[testsuiteName] 

819 except KeyError: 

820 self._testsuite = Testsuite(testsuiteName) 

821 self._testsuites[testsuiteName] = self._testsuite 

822 

823 def AddTestcase(self, testName: str) -> TestCase: 

824 if self._testsuite is None: 

825 self.SetTestsuite("default") 

826 

827 self._testcase = Testcase(testName) 

828 self._testsuite._testcases[testName] = self._testcase 

829 

830 return self._testcase 

831 

832 def SetTestcaseToplevel(self, toplevel: str) -> TestCase: 

833 if self._testcase is None: 833 ↛ 834line 833 didn't jump to line 834 because the condition on line 833 was never true

834 ex = OSVVMException("Can't set testcase toplevel, because no testcase was setup.") 

835 self._lastException = ex 

836 raise ex 

837 

838 self._testcase.SetToplevel(toplevel) 

839 

840 return self._testcase 

841 

842 def AddOption(self, option: Option) -> int: 

843 optionID = id(option) 

844 self._options[optionID] = option 

845 

846 return optionID 

847 

848 

849osvvmContext: Context = Context() 

850""" 

851Global OSVVM processing context. 

852 

853:type: Context 

854"""