Coverage for pyEDAA/ToolSetup/__init__.py: 67%
157 statements
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-13 18:11 +0000
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-13 18:11 +0000
1# ==================================================================================================================== #
2# _____ ____ _ _ _____ _ ____ _ #
3# _ __ _ _| ____| _ \ / \ / \ |_ _|__ ___ | / ___| ___| |_ _ _ _ __ #
4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |/ _ \ / _ \| \___ \ / _ \ __| | | | '_ \ #
5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| | (_) | (_) | |___) | __/ |_| |_| | |_) | #
6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_|\___/ \___/|_|____/ \___|\__|\__,_| .__/ #
7# |_| |___/ |_| #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2021-2026 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#
31"""Package to support configuring EDA tools for usage with pyEDAA.CLITool."""
32__author__ = "Patrick Lehmann"
33__email__ = "Paebbels@gmail.com"
34__copyright__ = "2014-2026, Patrick Lehmann"
35__license__ = "Apache License, Version 2.0"
36__version__ = "0.5.1"
37__keywords__ = ["configuration", "eda", "installation", "selection"]
38__project_url__ = "https://github.com/edaa-org/pyEDAA.ToolSetup"
39__documentation_url__ = "https://edaa-org.github.io/pyEDAA.ToolSetup"
40__issue_tracker_url__ = "https://GitHub.com/edaa-org/pyEDAA.ToolSetup/issues"
43from pathlib import Path
44from typing import Dict, ClassVar, cast
46from pyTooling.Decorators import export
47from pyTooling.Exceptions import ExceptionBase
48from pyTooling.Configuration import Dictionary
49from pyTooling.Configuration.YAML import Configuration
51from .DataModel import (
52 Installation as DM_Installation,
53 Vendor as DM_Vendor,
54 Tool as DM_Tool,
55 ToolInstance as DM_ToolInstance
56)
59class ToolChainException(ExceptionBase):
60 """Base-class for all pyEDAA.ToolSetup specific exceptions."""
62class ConfigurationException(ExceptionBase):
63 """``ConfigurationException`` is raise while running configuration or database
64 tasks in pyIPCMI
65 """
67class SkipConfigurationException(ExceptionBase):
68 """``SkipConfigurationException`` is a :py:exc:`ConfigurationException`,
69 which can be skipped.
70 """
72class ConfigurationMixIn:
73 _config: Dictionary
75 def __init__(self, config: Dictionary) -> None:
76 self._config = config
79@export
80class ToolInstance(DM_ToolInstance, ConfigurationMixIn):
81 def __init__(self, config: Dictionary, parent: "Tool") -> None:
82 name = config.Key
83 installationDirectory = Path(config["InstallationDirectory"])
84 binaryDirectory = Path(config["BinaryDirectory"])
85 version = config["Version"]
87 super().__init__(installationDirectory, binaryDirectory, version, parent=parent)
88 ConfigurationMixIn.__init__(self, config)
91@export
92class Tool(DM_Tool, ConfigurationMixIn):
93 def __init__(self, config: Dictionary, parent: "Vendor") -> None:
94 name = config.Key
96 super().__init__(name, parent=parent)
97 ConfigurationMixIn.__init__(self, config)
99 @property
100 def Default(self) -> ToolInstance:
101 return self._LoadVariant("Default")
103 def _LoadVariant(self, key: str) -> ToolInstance:
104 if key not in self._variants: 104 ↛ 108line 104 didn't jump to line 108 because the condition on line 104 was always true
105 instance = self._instanceClass(self._config[key], parent=self)
106 self._variants[key] = instance
107 else:
108 instance = self._variants[key]
110 return instance
112 def _LoadAllVariants(self) -> None:
113 if self._allLoaded:
114 return
116 for key in self._config:
117 if key not in self._variants:
118 self._variants[key] = ToolInstance(self._config[key], parent=self)
120 self._allLoaded = True
123@export
124class Vendor(DM_Vendor, ConfigurationMixIn):
125 _toolClasses: ClassVar[Dict[str, Tool]]
127 def __init__(self, config: Dictionary, parent: "Installations") -> None:
128 name = config.Key
129 installationDirectory = Path(config["InstallationDirectory"])
131 super().__init__(name, installationDirectory, parent=parent)
132 ConfigurationMixIn.__init__(self, config)
134 def _LoadTool(self, key: str) -> Tool:
135 if key not in self._tools: 135 ↛ 140line 135 didn't jump to line 140 because the condition on line 135 was always true
136 cls = self._toolClasses[key]
137 tool = cls(self._config[key], parent=self)
138 self._tools[key] = tool
139 else:
140 tool = self._tools[key]
142 return tool
144 def _LoadAllTools(self) -> None:
145 if self._allLoaded:
146 return
148 for key in self._config:
149 if key not in self._tools:
150 cls = self._toolClasses[key]
151 self._tools[key] = cls(self._config[key], parent=self)
153 self._allLoaded = True
156@export
157class Installations(DM_Installation):
158 from .Aldec import ActiveHDL, RivieraPRO, Aldec
159 from .OpenSource.GHDL import GHDL
160 from .IntelFPGA import Quartus, Altera, IntelFPGA
161 from .Lattice import Diamond, Lattice
162 from .OpenSource import OpenSource
163 from .OpenSource.GTKWave import GTKWave
164 from .SiemensEDA import ModelSim, QuestaSim, MentorGraphics
165 from .SystemTools import Git, SystemTools
166 from .Xilinx import ISE, Vivado, VivadoSDK, Vitis, Xilinx
168 _config: Configuration
169 _vendorClasses: Dict[str, Vendor] = {
170 "Aldec": Aldec,
171 "Altera": Altera,
172 "IntelFPGA": IntelFPGA,
173 "Lattice": Lattice,
174 "MentorGraphics": MentorGraphics,
175 "Xilinx": Xilinx,
176 "SystemTools": SystemTools,
177 "OpenSource": OpenSource
178 }
180 def __init__(self, yamlFile: Path) -> None:
181 super().__init__()
182 self._config = Configuration(yamlFile)
184 def _LoadVendor(self, key: str) -> Vendor:
185 cls = self._vendorClasses[key]
186 vendor = cls(self._config["Installations"][key], parent=self)
187 self._vendors[key] = vendor
189 return vendor
191 def _LoadAllVendors(self) -> None:
192 if self._allLoaded:
193 return
195 for key in self._config["Installations"]:
196 if key not in self._vendors:
197 cls = self._vendorClasses[key]
198 self._vendors[key] = cls(self._config["Installations"][key], parent=self)
200 self._allLoaded = True
202 @property
203 def Aldec(self) -> Aldec:
204 from .Aldec import Aldec
205 return cast(Aldec, self.__getitem__("Aldec"))
207 @property
208 def Altera(self) -> Altera:
209 from .IntelFPGA import Altera
210 return cast(Altera, self.__getitem__("Altera"))
212 @property
213 def IntelFPGA(self) -> IntelFPGA:
214 from .IntelFPGA import IntelFPGA
215 return cast(IntelFPGA, self.__getitem__("IntelFPGA"))
217 @property
218 def Lattice(self) -> Lattice:
219 from .Lattice import Lattice
220 return cast(Lattice, self.__getitem__("Lattice"))
222 @property
223 def MentorGraphics(self) -> MentorGraphics:
224 from .SiemensEDA import MentorGraphics
225 return cast(MentorGraphics, self.__getitem__("MentorGraphics"))
227 @property
228 def OpenSource(self) -> OpenSource:
229 from .OpenSource import OpenSource
230 return cast(OpenSource, self.__getitem__("OpenSource"))
232 @property
233 def SiemensEDA(self) -> SiemensEDA:
234 from .SiemensEDA import SiemensEDA
235 return cast(SiemensEDA, self.__getitem__("SiemensEDA"))
237 @property
238 def SystemTools(self) -> SystemTools:
239 from .SystemTools import SystemTools
240 return cast(SystemTools, self.__getitem__("SystemTools"))
242 @property
243 def Xilinx(self) -> Xilinx:
244 from .Xilinx import Xilinx
245 return cast(Xilinx, self.__getitem__("Xilinx"))
247 @property
248 def ActiveHDL(self) -> ActiveHDL:
249 raise NotImplementedError()
251 @property
252 def RivieraPRO(self) -> RivieraPRO:
253 raise NotImplementedError()
255 @property
256 def Diamond(self) -> Diamond:
257 raise NotImplementedError()
259 @property
260 def Quartus(self) -> Quartus:
261 raise NotImplementedError()
263 @property
264 def ModelSim(self) -> ModelSim:
265 raise NotImplementedError()
267 @property
268 def QuestaSim(self) -> QuestaSim:
269 raise NotImplementedError()
271 @property
272 def Vivado(self) -> Vivado:
273 raise NotImplementedError()
275 @property
276 def VivadoSDK(self) -> VivadoSDK:
277 raise NotImplementedError()
279 @property
280 def Vitis(self) -> Vitis:
281 raise NotImplementedError()