Coverage for sphinx_reports/DataModel/CodeCoverage.py: 71%
152 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-09 22:12 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-09 22:12 +0000
1# ==================================================================================================================== #
2# _ _ _ #
3# ___ _ __ | |__ (_)_ __ __ __ _ __ ___ _ __ ___ _ __| |_ ___ #
4# / __| '_ \| '_ \| | '_ \\ \/ /____| '__/ _ \ '_ \ / _ \| '__| __/ __| #
5# \__ \ |_) | | | | | | | |> <_____| | | __/ |_) | (_) | | | |_\__ \ #
6# |___/ .__/|_| |_|_|_| |_/_/\_\ |_| \___| .__/ \___/|_| \__|___/ #
7# |_| |_| #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2023-2025 Patrick Lehmann - Bötzingen, 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"""
32**Abstract documentation coverage data model for Python code.**
33"""
34from pathlib import Path
35from typing import Optional as Nullable, Dict, Union, Generic, TypeVar
37from pyTooling.Decorators import export, readonly
38from pyEDAA.Reports.DocumentationCoverage.Python import PackageCoverage
41_ParentType = TypeVar("_ParentType", bound="Base")
44@export
45class Base(Generic[_ParentType]):
46 _name: str
47 _parent: Nullable[_ParentType]
49 def __init__(self, name: str, parent: Nullable[_ParentType] = None) -> None:
50 self._name = name
51 self._parent = parent
53 @readonly
54 def Name(self) -> str:
55 return self._name
57 @readonly
58 def Parent(self) -> Nullable[_ParentType]:
59 return self._parent
62@export
63class Coverage(Base[_ParentType], Generic[_ParentType]):
64 _file: Path
66 _totalStatements: int
67 _excludedStatements: int
68 _coveredStatements: int
69 _missingStatements: int
70 _totalBranches: int
71 _partialBranches: int
73 _coverage: float
75 def __init__(self, name: str, file: Path, parent: Nullable[_ParentType] = None) -> None:
76 super().__init__(name, parent)
77 self._file = file
79 self._totalStatements = 0
80 self._excludedStatements = 0
81 self._coveredStatements = 0
82 self._missingStatements = 0
84 self._totalBranches = 0
85 self._coveredBranches = 0
86 self._partialBranches = 0
87 self._missingBranches = 0
89 self._coverage = -1.0
91 @readonly
92 def File(self) -> Path:
93 return self._file
95 @readonly
96 def TotalStatements(self) -> int:
97 return self._totalStatements
99 @readonly
100 def ExcludedStatements(self) -> int:
101 return self._excludedStatements
103 @readonly
104 def CoveredStatements(self) -> int:
105 return self._coveredStatements
107 @readonly
108 def MissingStatements(self) -> int:
109 return self._missingStatements
111 @readonly
112 def StatementCoverage(self) -> float:
113 if self._totalStatements <= 0:
114 return 0.0
116 return self._coveredStatements / self._totalStatements
118 @readonly
119 def TotalBranches(self) -> int:
120 return self._totalBranches
122 @readonly
123 def CoveredBranches(self) -> int:
124 return self._coveredBranches
126 @readonly
127 def PartialBranches(self) -> int:
128 return self._partialBranches
130 @readonly
131 def MissingBranches(self) -> int:
132 return self._missingBranches
134 @readonly
135 def BranchCoverage(self) -> float:
136 if self._totalBranches <= 0:
137 return 0.0
139 return (self._coveredBranches + self._partialBranches) / self._totalBranches
141 @readonly
142 def Coverage(self) -> float:
143 return self._coverage
146@export
147class ModuleCoverage(Coverage["PackageCoverage"]):
148 def __init__(self, name: str, file: Path, parent: Nullable["PackageCoverage"] = None) -> None:
149 super().__init__(name, file, parent)
151 if parent is not None: 151 ↛ 152line 151 didn't jump to line 152 because the condition on line 151 was never true
152 parent._modules[name] = self
155@export
156class PackageCoverage(Coverage["PackageCoverage"]):
157 _modules: Dict[str, ModuleCoverage]
158 _packages: Dict[str, "PackageCoverage"]
160 def __init__(self, name: str, file: Path, parent: Nullable["PackageCoverage"] = None) -> None:
161 super().__init__(name, file, parent)
163 if parent is not None: 163 ↛ 164line 163 didn't jump to line 164 because the condition on line 163 was never true
164 parent._packages[name] = self
166 self._modules = {}
167 self._packages = {}
169 @readonly
170 def FileCount(self) -> int:
171 return self.TotalModuleCount
173 @readonly
174 def PackageCount(self) -> int:
175 return len(self._packages)
177 @readonly
178 def ModuleCount(self) -> int:
179 return 1 + len(self._modules)
181 @readonly
182 def TotalPackageCount(self) -> int:
183 return 1 + sum(p.TotalPackageCount for p in self._packages.values())
185 @readonly
186 def TotalModuleCount(self) -> int:
187 return 1 + sum(p.TotalModuleCount for p in self._packages.values()) + len(self._modules)
189 @readonly
190 def Packages(self) -> Dict[str, "PackageCoverage"]:
191 return self._packages
193 @readonly
194 def Modules(self) -> Dict[str, ModuleCoverage]:
195 return self._modules
197 @readonly
198 def AggregatedTotalStatements(self) -> int:
199 return (
200 self._totalStatements +
201 sum(p.AggregatedTotalStatements for p in self._packages.values()) +
202 sum(m._totalStatements for m in self._modules.values())
203 )
205 @readonly
206 def AggregatedExcludedStatements(self) -> int:
207 return (
208 self._excludedStatements +
209 sum(p.AggregatedExcludedStatements for p in self._packages.values()) +
210 sum(m._excludedStatements for m in self._modules.values())
211 )
213 @readonly
214 def AggregatedCoveredStatements(self) -> int:
215 return (
216 self._coveredStatements +
217 sum(p.AggregatedCoveredStatements for p in self._packages.values()) +
218 sum(m._coveredStatements for m in self._modules.values())
219 )
221 @readonly
222 def AggregatedMissingStatements(self) -> int:
223 return (
224 self._missingStatements +
225 sum(p.AggregatedMissingStatements for p in self._packages.values()) +
226 sum(m._missingStatements for m in self._modules.values())
227 )
229 @readonly
230 def AggregatedStatementCoverage(self) -> float:
231 return self.AggregatedCoveredStatements / self.AggregatedTotalStatements
233 @readonly
234 def AggregatedTotalBranches(self) -> int:
235 return (
236 self._totalBranches +
237 sum(p.AggregatedTotalBranches for p in self._packages.values()) +
238 sum(m._totalBranches for m in self._modules.values())
239 )
241 @readonly
242 def AggregatedCoveredBranches(self) -> int:
243 return (
244 self._coveredBranches +
245 sum(p.AggregatedCoveredBranches for p in self._packages.values()) +
246 sum(m._coveredBranches for m in self._modules.values())
247 )
249 @readonly
250 def AggregatedPartialBranches(self) -> int:
251 return (
252 self._partialBranches +
253 sum(p.AggregatedPartialBranches for p in self._packages.values()) +
254 sum(m._partialBranches for m in self._modules.values())
255 )
257 @readonly
258 def AggregatedMissingBranches(self) -> int:
259 return (
260 self._missingBranches +
261 sum(p.AggregatedMissingBranches for p in self._packages.values()) +
262 sum(m._missingBranches for m in self._modules.values())
263 )
265 @readonly
266 def AggregatedBranchCoverage(self) -> float:
267 return (self.AggregatedCoveredBranches + self.AggregatedPartialBranches) / self.AggregatedTotalBranches
269 def __getitem__(self, key: str) -> Union["PackageCoverage", ModuleCoverage]:
270 try:
271 return self._modules[key]
272 except KeyError:
273 return self._packages[key]