Coverage for pyEDAA/Reports/CodeCoverage/UCIS/Coverpoints.py: 73%

249 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-21 23:49 +0000

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

2# _____ ____ _ _ ____ _ # 

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

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) / _ \ '_ \ / _ \| '__| __/ __| # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| _ < __/ |_) | (_) | | | |_\__ \ # 

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

7# |_| |___/ |_| # 

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2026-2026 Electronic Design Automation Abstraction (EDA²) # 

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""" 

32The coverpoints of the covergroup coverage of the UCIS XML interchange format: their bins, and the value ranges or 

33sequences a bin counts. 

34""" 

35from __future__ import annotations 

36 

37from typing import TYPE_CHECKING, Iterable, Optional as Nullable, Self 

38 

39from lxml.etree import _Element 

40from pyTooling.Common import getFullyQualifiedName 

41from pyTooling.Decorators import export, readonly 

42from pyTooling.MetaClasses import ExtendedType, abstractclass 

43 

44from pyEDAA.Reports.CodeCoverage.UCIS.Bins import BinContents 

45from pyEDAA.Reports.CodeCoverage.UCIS.CoverOptions import CoverpointOptions 

46from pyEDAA.Reports.CodeCoverage.UCIS.Elements import Base, UserAttribute 

47 

48if TYPE_CHECKING: 48 ↛ 49line 48 didn't jump to line 49 because the condition on line 48 was never true

49 from pyEDAA.Reports.CodeCoverage.UCIS.Covergroups import CovergroupInstance 

50 

51 

52@export 

53@abstractclass 

54class BinBase(Base): 

55 """ 

56 Base-class of the bins of a coverpoint or a cross: the bin's kind, alias, and - as some tools write them - name and 

57 key. 

58 """ 

59 

60 _binType: str #: Kind of the bin, e.g. ``default``, ``ignore`` or ``illegal``. 

61 _alias: Nullable[str] #: An alias of the bin's name. 

62 _name: Nullable[str] #: Name of the bin. 

63 _key: Nullable[str] #: UCIS key of the bin. 

64 

65 def __init__( 

66 self, 

67 binType: str, 

68 alias: Nullable[str] = None, 

69 name: Nullable[str] = None, 

70 key: Nullable[str] = None, 

71 userAttributes: Nullable[Iterable[UserAttribute]] = None 

72 ) -> None: 

73 """ 

74 Initialize the bin's kind, alias, name and key. 

75 

76 :param binType: Kind of the bin, e.g. ``default``, ``ignore`` or ``illegal``. 

77 :param alias: Optional, an alias of the bin's name. Default: ``None``. 

78 :param name: Optional, name of the bin; the standard's schema has none, pyucis writes it. Default: 

79 ``None``. 

80 :param key: Optional, UCIS key of the bin; the standard's schema has none, pyucis writes it. Default: 

81 ``None``. 

82 :param userAttributes: Optional, the user-defined attributes. Default: ``None``. 

83 :raises TypeError: If parameter ``userAttributes`` isn't iterable. 

84 :raises TypeError: If parameter ``userAttributes`` contains an element not of type 

85 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. 

86 :raises ValueError: If parameter ``binType`` is ``None``. 

87 :raises TypeError: If parameter ``binType`` isn't of type :class:`str`. 

88 :raises TypeError: If parameter ``alias``, ``name`` or ``key`` isn't of type :class:`str`. 

89 """ 

90 super().__init__(userAttributes) 

91 

92 if binType is None: 92 ↛ 93line 92 didn't jump to line 93 because the condition on line 92 was never true

93 raise ValueError("Parameter 'binType' is None.") 

94 elif not isinstance(binType, str): 94 ↛ 95line 94 didn't jump to line 95 because the condition on line 94 was never true

95 ex = TypeError("Parameter 'binType' is not of type 'str'.") 

96 ex.add_note(f"Got type '{getFullyQualifiedName(binType)}'.") 

97 raise ex 

98 

99 for parameterName, value in ( 

100 ("alias", alias), 

101 ("name", name), 

102 ("key", key) 

103 ): 

104 if value is not None and not isinstance(value, str): 104 ↛ 105line 104 didn't jump to line 105 because the condition on line 104 was never true

105 ex = TypeError(f"Parameter '{parameterName}' is not of type 'str'.") 

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

107 raise ex 

108 

109 self._binType = binType 

110 self._alias = alias 

111 self._name = name 

112 self._key = key 

113 

114 @readonly 

115 def BinType(self) -> str: 

116 """ 

117 Read-only property to access the kind of the bin (:attr:`_binType`). 

118 

119 :returns: The kind, as stated, e.g. ``default``, ``ignore`` or ``illegal``. 

120 """ 

121 return self._binType 

122 

123 @readonly 

124 def Alias(self) -> Nullable[str]: 

125 """ 

126 Read-only property to access the alias of the bin's name (:attr:`_alias`). 

127 

128 :returns: The alias; ``None``, if the report states none. 

129 """ 

130 return self._alias 

131 

132 @readonly 

133 def Name(self) -> Nullable[str]: 

134 """ 

135 Read-only property to access the name of the bin (:attr:`_name`). 

136 

137 :returns: The name; ``None``, if the report states none. 

138 """ 

139 return self._name 

140 

141 @readonly 

142 def Key(self) -> Nullable[str]: 

143 """ 

144 Read-only property to access the UCIS key of the bin (:attr:`_key`). 

145 

146 :returns: The key; ``None``, if the report states none. 

147 """ 

148 return self._key 

149 

150 

151@export 

152class ValueRange(metaclass=ExtendedType, slots=True): 

153 """ 

154 A ``<range>`` of a coverpoint's bin: a range of values, and how often the coverpoint's expression had one of them. 

155 """ 

156 

157 _parent: Nullable[CoverpointBin] #: The coverpoint bin the range belongs to. 

158 _from: int #: The range's lowest value. 

159 _to: int #: The range's highest value. 

160 _contents: BinContents #: How often the expression had a value of the range. 

161 

162 def __init__(self, fromValue: int, toValue: int, contents: BinContents) -> None: 

163 """ 

164 Initialize the range of values. 

165 

166 The coverpoint bin owning the range takes it as a parameter and becomes its parent. 

167 

168 :param fromValue: The range's lowest value. 

169 :param toValue: The range's highest value; the lowest one again for a single value. 

170 :param contents: How often the expression had a value of the range. 

171 :raises ValueError: If parameter ``fromValue`` or ``toValue`` is ``None``. 

172 :raises TypeError: If parameter ``fromValue`` or ``toValue`` isn't of type :class:`int`. 

173 :raises ValueError: If parameter ``contents`` is ``None``. 

174 :raises TypeError: If parameter ``contents`` isn't of type 

175 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Bins.BinContents`. 

176 """ 

177 for parameterName, value in ( 

178 ("fromValue", fromValue), 

179 ("toValue", toValue) 

180 ): 

181 if value is None: 181 ↛ 182line 181 didn't jump to line 182 because the condition on line 181 was never true

182 raise ValueError(f"Parameter '{parameterName}' is None.") 

183 elif not isinstance(value, int) or isinstance(value, bool): 183 ↛ 184line 183 didn't jump to line 184 because the condition on line 183 was never true

184 ex = TypeError(f"Parameter '{parameterName}' is not of type 'int'.") 

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

186 raise ex 

187 

188 if contents is None: 188 ↛ 189line 188 didn't jump to line 189 because the condition on line 188 was never true

189 raise ValueError("Parameter 'contents' is None.") 

190 elif not isinstance(contents, BinContents): 190 ↛ 191line 190 didn't jump to line 191 because the condition on line 190 was never true

191 ex = TypeError("Parameter 'contents' is not of type 'BinContents'.") 

192 ex.add_note(f"Got type '{getFullyQualifiedName(contents)}'.") 

193 raise ex 

194 

195 self._parent = None 

196 self._from = fromValue 

197 self._to = toValue 

198 self._contents = contents 

199 

200 @classmethod 

201 def Parse(cls, element: _Element) -> Self: 

202 """ 

203 Parse a range of values from its ``<range>`` element. 

204 

205 :param element: The ``<range>`` element. 

206 :returns: The range. 

207 """ 

208 return cls( 

209 int(element.attrib["from"]), 

210 int(element.attrib["to"]), 

211 BinContents.Parse(element.find("{*}contents")) 

212 ) 

213 

214 @readonly 

215 def Parent(self) -> Nullable[CoverpointBin]: 

216 """ 

217 Read-only property to access the coverpoint bin the range belongs to (:attr:`_parent`). 

218 

219 :returns: The coverpoint bin; ``None``, if the range belongs to none. 

220 """ 

221 return self._parent 

222 

223 @readonly 

224 def From(self) -> int: 

225 """ 

226 Read-only property to access the range's lowest value (:attr:`_from`). 

227 

228 :returns: The value. 

229 """ 

230 return self._from 

231 

232 @readonly 

233 def To(self) -> int: 

234 """ 

235 Read-only property to access the range's highest value (:attr:`_to`). 

236 

237 :returns: The value. 

238 """ 

239 return self._to 

240 

241 @readonly 

242 def Contents(self) -> BinContents: 

243 """ 

244 Read-only property to access how often the expression had a value of the range (:attr:`_contents`). 

245 

246 :returns: The contents: the count and the tests. 

247 """ 

248 return self._contents 

249 

250 

251@export 

252class ValueSequence(metaclass=ExtendedType, slots=True): 

253 """ 

254 A ``<sequence>`` of a coverpoint's bin: a sequence of values, and how often the coverpoint's expression had them one 

255 after the other. 

256 """ 

257 

258 _parent: Nullable[CoverpointBin] #: The coverpoint bin the sequence belongs to. 

259 _values: list[int] #: The values, from the first one. 

260 _contents: BinContents #: How often the expression had the values one after the other. 

261 

262 def __init__(self, values: Iterable[int], contents: BinContents) -> None: 

263 """ 

264 Initialize the sequence of values. 

265 

266 The coverpoint bin owning the sequence takes it as a parameter and becomes its parent. 

267 

268 :param values: The values, from the first one. 

269 :param contents: How often the expression had the values one after the other. 

270 :raises ValueError: If parameter ``contents`` is ``None``. 

271 :raises TypeError: If parameter ``contents`` isn't of type 

272 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Bins.BinContents`. 

273 :raises ValueError: If parameter ``values`` is ``None``. 

274 :raises TypeError: If parameter ``values`` isn't iterable. 

275 :raises TypeError: If parameter ``values`` contains an element not of type :class:`int`. 

276 :raises ValueError: If parameter ``values`` is empty. 

277 """ 

278 if contents is None: 278 ↛ 279line 278 didn't jump to line 279 because the condition on line 278 was never true

279 raise ValueError("Parameter 'contents' is None.") 

280 elif not isinstance(contents, BinContents): 280 ↛ 281line 280 didn't jump to line 281 because the condition on line 280 was never true

281 ex = TypeError("Parameter 'contents' is not of type 'BinContents'.") 

282 ex.add_note(f"Got type '{getFullyQualifiedName(contents)}'.") 

283 raise ex 

284 

285 self._parent = None 

286 self._values = [] 

287 self._contents = contents 

288 

289 if values is None: 289 ↛ 290line 289 didn't jump to line 290 because the condition on line 289 was never true

290 raise ValueError("Parameter 'values' is None.") 

291 elif not isinstance(values, Iterable): 291 ↛ 292line 291 didn't jump to line 292 because the condition on line 291 was never true

292 ex = TypeError("Parameter 'values' is not iterable.") 

293 ex.add_note(f"Got type '{getFullyQualifiedName(values)}'.") 

294 raise ex 

295 

296 for value in values: 

297 if not isinstance(value, int) or isinstance(value, bool): 297 ↛ 298line 297 didn't jump to line 298 because the condition on line 297 was never true

298 ex = TypeError("Parameter 'values' contains an element not of type 'int'.") 

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

300 raise ex 

301 

302 self._values.append(value) 

303 

304 if len(self._values) == 0: 

305 raise ValueError("Parameter 'values' is empty.") 

306 

307 @classmethod 

308 def Parse(cls, element: _Element) -> Self: 

309 """ 

310 Parse a sequence of values from its ``<sequence>`` element. 

311 

312 :param element: The ``<sequence>`` element. 

313 :returns: The sequence. 

314 """ 

315 return cls( 

316 [int(valueElement.text) for valueElement in element.iterfind("{*}seqValue")], 

317 BinContents.Parse(element.find("{*}contents")) 

318 ) 

319 

320 @readonly 

321 def Parent(self) -> Nullable[CoverpointBin]: 

322 """ 

323 Read-only property to access the coverpoint bin the sequence belongs to (:attr:`_parent`). 

324 

325 :returns: The coverpoint bin; ``None``, if the sequence belongs to none. 

326 """ 

327 return self._parent 

328 

329 @readonly 

330 def Values(self) -> list[int]: 

331 """ 

332 Read-only property to access the values (:attr:`_values`). 

333 

334 :returns: The values, from the first one. 

335 """ 

336 return self._values 

337 

338 @readonly 

339 def Contents(self) -> BinContents: 

340 """ 

341 Read-only property to access how often the expression had the values one after the other (:attr:`_contents`). 

342 

343 :returns: The contents: the count and the tests. 

344 """ 

345 return self._contents 

346 

347 

348@export 

349class CoverpointBin(BinBase): 

350 """ 

351 A ``<coverpointBin>`` of a coverpoint: its kind, and the ranges or sequences of values it counts. 

352 """ 

353 

354 _parent: Nullable[Coverpoint] #: The coverpoint the bin belongs to. 

355 _ranges: list[ValueRange] #: The ranges of values the bin counts. 

356 _sequences: list[ValueSequence] #: The sequences of values the bin counts. 

357 

358 def __init__( 

359 self, 

360 binType: str, 

361 ranges: Nullable[Iterable[ValueRange]] = None, 

362 sequences: Nullable[Iterable[ValueSequence]] = None, 

363 alias: Nullable[str] = None, 

364 name: Nullable[str] = None, 

365 key: Nullable[str] = None, 

366 userAttributes: Nullable[Iterable[UserAttribute]] = None, 

367 *, 

368 parent: Nullable[Coverpoint] = None 

369 ) -> None: 

370 """ 

371 Initialize the coverpoint bin, become its ranges' and sequences' parent, and append it to the bins of its 

372 coverpoint. 

373 

374 :param binType: Kind of the bin, e.g. ``default``, ``ignore`` or ``illegal``. 

375 :param ranges: Optional, the ranges of values the bin counts. Default: ``None``. 

376 :param sequences: Optional, the sequences of values the bin counts. Default: ``None``. 

377 :param alias: Optional, an alias of the bin's name. Default: ``None``. 

378 :param name: Optional, name of the bin, as pyucis writes it. Default: ``None``. 

379 :param key: Optional, UCIS key of the bin, as pyucis writes it. Default: ``None``. 

380 :param userAttributes: Optional, the user-defined attributes. Default: ``None``. 

381 :param parent: Optional, the coverpoint the bin belongs to. Default: ``None``. 

382 :raises TypeError: If parameter ``userAttributes`` isn't iterable. 

383 :raises TypeError: If parameter ``userAttributes`` contains an element not of type 

384 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. 

385 :raises ValueError: If parameter ``binType`` is ``None``. 

386 :raises TypeError: If parameter ``binType`` isn't of type :class:`str`. 

387 :raises TypeError: If parameter ``alias``, ``name`` or ``key`` isn't of type :class:`str`. 

388 :raises TypeError: If parameter ``parent`` isn't of type :class:`Coverpoint`. 

389 :raises TypeError: If parameter ``ranges`` isn't iterable. 

390 :raises TypeError: If parameter ``ranges`` contains an element not of type :class:`ValueRange`. 

391 :raises TypeError: If parameter ``sequences`` isn't iterable. 

392 :raises TypeError: If parameter ``sequences`` contains an element not of type :class:`ValueSequence`. 

393 """ 

394 super().__init__(binType, alias, name, key, userAttributes) 

395 

396 if parent is not None and not isinstance(parent, Coverpoint): 396 ↛ 397line 396 didn't jump to line 397 because the condition on line 396 was never true

397 ex = TypeError("Parameter 'parent' is not of type 'Coverpoint'.") 

398 ex.add_note(f"Got type '{getFullyQualifiedName(parent)}'.") 

399 raise ex 

400 

401 self._parent = parent 

402 self._ranges = [] 

403 self._sequences = [] 

404 

405 if ranges is not None: 405 ↛ 420line 405 didn't jump to line 420 because the condition on line 405 was always true

406 if not isinstance(ranges, Iterable): 406 ↛ 407line 406 didn't jump to line 407 because the condition on line 406 was never true

407 ex = TypeError("Parameter 'ranges' is not iterable.") 

408 ex.add_note(f"Got type '{getFullyQualifiedName(ranges)}'.") 

409 raise ex 

410 

411 for valueRange in ranges: 

412 if not isinstance(valueRange, ValueRange): 412 ↛ 413line 412 didn't jump to line 413 because the condition on line 412 was never true

413 ex = TypeError("Parameter 'ranges' contains an element not of type 'ValueRange'.") 

414 ex.add_note(f"Got type '{getFullyQualifiedName(valueRange)}'.") 

415 raise ex 

416 

417 valueRange._parent = self 

418 self._ranges.append(valueRange) 

419 

420 if sequences is not None: 

421 if not isinstance(sequences, Iterable): 421 ↛ 422line 421 didn't jump to line 422 because the condition on line 421 was never true

422 ex = TypeError("Parameter 'sequences' is not iterable.") 

423 ex.add_note(f"Got type '{getFullyQualifiedName(sequences)}'.") 

424 raise ex 

425 

426 for valueSequence in sequences: 

427 if not isinstance(valueSequence, ValueSequence): 427 ↛ 428line 427 didn't jump to line 428 because the condition on line 427 was never true

428 ex = TypeError("Parameter 'sequences' contains an element not of type 'ValueSequence'.") 

429 ex.add_note(f"Got type '{getFullyQualifiedName(valueSequence)}'.") 

430 raise ex 

431 

432 valueSequence._parent = self 

433 self._sequences.append(valueSequence) 

434 

435 if parent is not None: 435 ↛ exitline 435 didn't return from function '__init__' because the condition on line 435 was always true

436 parent._bins.append(self) 

437 

438 @classmethod 

439 def Parse(cls, element: _Element, *, parent: Nullable[Coverpoint] = None) -> Self: 

440 """ 

441 Parse a coverpoint bin, its ranges and sequences from its ``<coverpointBin>`` element. 

442 

443 :param element: The ``<coverpointBin>`` element. 

444 :param parent: Optional, the coverpoint the bin belongs to. Default: ``None``. 

445 :returns: The coverpoint bin. 

446 :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. 

447 """ 

448 return cls( 

449 element.attrib["type"], 

450 [ValueRange.Parse(rangeElement) for rangeElement in element.iterfind("{*}range")], 

451 [ValueSequence.Parse(sequenceElement) for sequenceElement in element.iterfind("{*}sequence")], 

452 element.attrib.get("alias"), 

453 element.attrib.get("name"), 

454 element.attrib.get("key"), 

455 cls._ParseUserAttributes(element), 

456 parent=parent 

457 ) 

458 

459 @readonly 

460 def Parent(self) -> Nullable[Coverpoint]: 

461 """ 

462 Read-only property to access the coverpoint the bin belongs to (:attr:`_parent`). 

463 

464 :returns: The coverpoint; ``None``, if the bin belongs to none. 

465 """ 

466 return self._parent 

467 

468 @readonly 

469 def Ranges(self) -> list[ValueRange]: 

470 """ 

471 Read-only property to access the ranges of values the bin counts (:attr:`_ranges`). 

472 

473 :returns: The ranges, in the order the report lists them; empty for a bin of sequences. 

474 """ 

475 return self._ranges 

476 

477 @readonly 

478 def Sequences(self) -> list[ValueSequence]: 

479 """ 

480 Read-only property to access the sequences of values the bin counts (:attr:`_sequences`). 

481 

482 :returns: The sequences, in the order the report lists them; empty for a bin of ranges. 

483 """ 

484 return self._sequences 

485 

486 

487@export 

488class Coverpoint(Base): 

489 """ 

490 A ``<coverpoint>`` of a covergroup instance: its expression, options and bins. 

491 """ 

492 

493 _parent: Nullable[CovergroupInstance] #: The covergroup instance the coverpoint belongs to. 

494 _name: str #: Name of the coverpoint. 

495 _key: str #: UCIS key of the coverpoint. 

496 _options: CoverpointOptions #: The options of the coverpoint. 

497 _alias: Nullable[str] #: An alias of the coverpoint's name. 

498 _expression: Nullable[str] #: The expression the coverpoint samples. 

499 _bins: list[CoverpointBin] #: The bins. 

500 

501 def __init__( 

502 self, 

503 name: str, 

504 key: str, 

505 options: CoverpointOptions, 

506 alias: Nullable[str] = None, 

507 expression: Nullable[str] = None, 

508 userAttributes: Nullable[Iterable[UserAttribute]] = None, 

509 *, 

510 parent: Nullable[CovergroupInstance] = None 

511 ) -> None: 

512 """ 

513 Initialize the coverpoint, and append it to the coverpoints of its covergroup instance. 

514 

515 Its bins are added by creating them with this coverpoint as their parent. 

516 

517 :param name: Name of the coverpoint, e.g. ``cvpt_a``. 

518 :param key: UCIS key of the coverpoint. 

519 :param options: The options of the coverpoint. 

520 :param alias: Optional, an alias of the coverpoint's name. Default: ``None``. 

521 :param expression: Optional, the expression the coverpoint samples, e.g. ``a``. Default: ``None``. 

522 :param userAttributes: Optional, the user-defined attributes. Default: ``None``. 

523 :param parent: Optional, the covergroup instance the coverpoint belongs to. Default: ``None``. 

524 :raises TypeError: If parameter ``userAttributes`` isn't iterable. 

525 :raises TypeError: If parameter ``userAttributes`` contains an element not of type 

526 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. 

527 :raises ValueError: If parameter ``name`` or ``key`` is ``None``. 

528 :raises TypeError: If parameter ``name`` or ``key`` isn't of type :class:`str`. 

529 :raises ValueError: If parameter ``options`` is ``None``. 

530 :raises TypeError: If parameter ``options`` isn't of type 

531 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.CoverOptions.CoverpointOptions`. 

532 :raises TypeError: If parameter ``alias`` or ``expression`` isn't of type :class:`str`. 

533 :raises TypeError: If parameter ``parent`` isn't of type 

534 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Covergroups.CovergroupInstance`. 

535 """ 

536 from pyEDAA.Reports.CodeCoverage.UCIS.Covergroups import CovergroupInstance 

537 

538 super().__init__(userAttributes) 

539 

540 for parameterName, value in ( 

541 ("name", name), 

542 ("key", key) 

543 ): 

544 if value is None: 544 ↛ 545line 544 didn't jump to line 545 because the condition on line 544 was never true

545 raise ValueError(f"Parameter '{parameterName}' is None.") 

546 elif not isinstance(value, str): 546 ↛ 547line 546 didn't jump to line 547 because the condition on line 546 was never true

547 ex = TypeError(f"Parameter '{parameterName}' is not of type 'str'.") 

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

549 raise ex 

550 

551 if options is None: 551 ↛ 552line 551 didn't jump to line 552 because the condition on line 551 was never true

552 raise ValueError("Parameter 'options' is None.") 

553 elif not isinstance(options, CoverpointOptions): 553 ↛ 554line 553 didn't jump to line 554 because the condition on line 553 was never true

554 ex = TypeError("Parameter 'options' is not of type 'CoverpointOptions'.") 

555 ex.add_note(f"Got type '{getFullyQualifiedName(options)}'.") 

556 raise ex 

557 

558 for parameterName, value in ( 

559 ("alias", alias), 

560 ("expression", expression) 

561 ): 

562 if value is not None and not isinstance(value, str): 562 ↛ 563line 562 didn't jump to line 563 because the condition on line 562 was never true

563 ex = TypeError(f"Parameter '{parameterName}' is not of type 'str'.") 

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

565 raise ex 

566 

567 if parent is not None and not isinstance(parent, CovergroupInstance): 567 ↛ 568line 567 didn't jump to line 568 because the condition on line 567 was never true

568 ex = TypeError("Parameter 'parent' is not of type 'CovergroupInstance'.") 

569 ex.add_note(f"Got type '{getFullyQualifiedName(parent)}'.") 

570 raise ex 

571 

572 self._parent = parent 

573 self._name = name 

574 self._key = key 

575 self._options = options 

576 self._alias = alias 

577 self._expression = expression 

578 self._bins = [] 

579 

580 if parent is not None: 580 ↛ exitline 580 didn't return from function '__init__' because the condition on line 580 was always true

581 parent._coverpoints.append(self) 

582 

583 @classmethod 

584 def Parse(cls, element: _Element, *, parent: Nullable[CovergroupInstance] = None) -> Self: 

585 """ 

586 Parse a coverpoint, its options and bins from its ``<coverpoint>`` element. 

587 

588 :param element: The ``<coverpoint>`` element. 

589 :param parent: Optional, the covergroup instance the coverpoint belongs to. Default: ``None``. 

590 :returns: The coverpoint. 

591 :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. 

592 """ 

593 coverpoint = cls( 

594 element.attrib["name"], 

595 element.attrib["key"], 

596 CoverpointOptions.Parse(element.find("{*}options")), 

597 element.attrib.get("alias"), 

598 element.attrib.get("exprString"), 

599 cls._ParseUserAttributes(element), 

600 parent=parent 

601 ) 

602 

603 for binElement in element.iterfind("{*}coverpointBin"): 

604 CoverpointBin.Parse(binElement, parent=coverpoint) 

605 

606 return coverpoint 

607 

608 @readonly 

609 def Parent(self) -> Nullable[CovergroupInstance]: 

610 """ 

611 Read-only property to access the covergroup instance the coverpoint belongs to (:attr:`_parent`). 

612 

613 :returns: The covergroup instance; ``None``, if the coverpoint belongs to none. 

614 """ 

615 return self._parent 

616 

617 @readonly 

618 def Name(self) -> str: 

619 """ 

620 Read-only property to access the name of the coverpoint (:attr:`_name`). 

621 

622 :returns: The name, as declared. 

623 """ 

624 return self._name 

625 

626 @readonly 

627 def Key(self) -> str: 

628 """ 

629 Read-only property to access the UCIS key of the coverpoint (:attr:`_key`). 

630 

631 :returns: The key, as stated. 

632 """ 

633 return self._key 

634 

635 @readonly 

636 def Options(self) -> CoverpointOptions: 

637 """ 

638 Read-only property to access the options of the coverpoint (:attr:`_options`). 

639 

640 :returns: The options. 

641 """ 

642 return self._options 

643 

644 @readonly 

645 def Alias(self) -> Nullable[str]: 

646 """ 

647 Read-only property to access the alias of the coverpoint's name (:attr:`_alias`). 

648 

649 :returns: The alias; ``None``, if the report states none. 

650 """ 

651 return self._alias 

652 

653 @readonly 

654 def Expression(self) -> Nullable[str]: 

655 """ 

656 Read-only property to access the expression the coverpoint samples (:attr:`_expression`). 

657 

658 :returns: The expression, e.g. ``a``; ``None``, if the report states none. 

659 """ 

660 return self._expression 

661 

662 @readonly 

663 def Bins(self) -> list[CoverpointBin]: 

664 """ 

665 Read-only property to access the bins (:attr:`_bins`). 

666 

667 :returns: The bins, in the order the report lists them. 

668 """ 

669 return self._bins