checkup 0.2.6__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {checkup-0.2.6 → checkup-0.2.8}/PKG-INFO +1 -1
- {checkup-0.2.6 → checkup-0.2.8}/pyproject.toml +1 -1
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/executor.py +89 -11
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/hub.py +31 -8
- {checkup-0.2.6 → checkup-0.2.8}/README.md +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/__init__.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/config.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/errors.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/graph.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/materializers/__init__.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/materializers/base.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/materializers/console.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/materializers/csv_file.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/materializers/database.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/materializers/html_report.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/metric.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/provider.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/providers/__init__.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/providers/tags.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/templates/metrics_report.html +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/types.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/utils.py +0 -0
- {checkup-0.2.6 → checkup-0.2.8}/src/checkup/validators.py +0 -0
|
@@ -54,7 +54,7 @@ class ProviderExecutor:
|
|
|
54
54
|
"""
|
|
55
55
|
|
|
56
56
|
def execute(
|
|
57
|
-
self, provider_set: list[Provider]
|
|
57
|
+
self, provider_set: list[Provider]
|
|
58
58
|
) -> tuple[Context, dict[str, Any], list[ProviderError]]:
|
|
59
59
|
"""Execute all providers and build namespaced context.
|
|
60
60
|
|
|
@@ -64,14 +64,9 @@ class ProviderExecutor:
|
|
|
64
64
|
|
|
65
65
|
Args:
|
|
66
66
|
provider_set: List of provider instances
|
|
67
|
-
fail_fast: If True, raise on first provider error.
|
|
68
|
-
If False, collect errors and continue.
|
|
69
67
|
|
|
70
68
|
Returns:
|
|
71
69
|
Tuple of (context dict, tags dict, list of errors)
|
|
72
|
-
|
|
73
|
-
Raises:
|
|
74
|
-
ProviderError: If fail_fast=True and a provider fails
|
|
75
70
|
"""
|
|
76
71
|
context: Context = {}
|
|
77
72
|
tags: dict[str, Any] = {}
|
|
@@ -89,8 +84,6 @@ class ProviderExecutor:
|
|
|
89
84
|
except Exception as e:
|
|
90
85
|
error = ProviderError(provider, e)
|
|
91
86
|
logger.error("Provider %s failed: %s", provider.name, e)
|
|
92
|
-
if fail_fast:
|
|
93
|
-
raise error from e
|
|
94
87
|
errors.append(error)
|
|
95
88
|
|
|
96
89
|
return context, tags, errors
|
|
@@ -113,6 +106,7 @@ class MetricCalculator:
|
|
|
113
106
|
context: Context,
|
|
114
107
|
tags: dict[str, Any],
|
|
115
108
|
provided_classes: set[type[Provider]],
|
|
109
|
+
failed_providers: dict[type[Provider], ProviderError] | None = None,
|
|
116
110
|
) -> list[Metric]:
|
|
117
111
|
"""Calculate all metrics in execution order.
|
|
118
112
|
|
|
@@ -124,13 +118,16 @@ class MetricCalculator:
|
|
|
124
118
|
context: Context dict from providers
|
|
125
119
|
tags: Tags dict to merge into metrics
|
|
126
120
|
provided_classes: Set of provider classes available
|
|
121
|
+
failed_providers: Dict mapping failed provider classes to their errors
|
|
127
122
|
|
|
128
123
|
Returns:
|
|
129
124
|
List of calculated metrics
|
|
130
125
|
"""
|
|
126
|
+
failed_providers = failed_providers or {}
|
|
131
127
|
logger.debug("Starting metric calculation for %d metrics", len(execution_order))
|
|
132
128
|
calculated: dict[type[Metric], Metric] = {}
|
|
133
129
|
skipped: set[type[Metric]] = set()
|
|
130
|
+
failed: set[type[Metric]] = set()
|
|
134
131
|
result_metrics: list[Metric] = []
|
|
135
132
|
|
|
136
133
|
i = 0
|
|
@@ -138,12 +135,24 @@ class MetricCalculator:
|
|
|
138
135
|
while i < len(execution_order):
|
|
139
136
|
metric_cls = execution_order[i]
|
|
140
137
|
|
|
141
|
-
# Check for skip conditions
|
|
138
|
+
# Check for skip conditions (missing providers)
|
|
142
139
|
if self._should_skip(metric_cls, provided_classes, skipped):
|
|
143
140
|
skipped.add(metric_cls)
|
|
144
141
|
i += 1
|
|
145
142
|
continue
|
|
146
143
|
|
|
144
|
+
# Check for failed provider dependencies
|
|
145
|
+
failed_deps = self._get_failed_providers(
|
|
146
|
+
metric_cls, failed_providers, failed
|
|
147
|
+
)
|
|
148
|
+
if failed_deps:
|
|
149
|
+
metric = self._create_failed_metric(metric_cls, tags, failed_deps)
|
|
150
|
+
calculated[metric_cls] = metric
|
|
151
|
+
result_metrics.append(metric)
|
|
152
|
+
failed.add(metric_cls)
|
|
153
|
+
i += 1
|
|
154
|
+
continue
|
|
155
|
+
|
|
147
156
|
# Start a new batch with this executor type
|
|
148
157
|
current_executor = metric_cls.executor
|
|
149
158
|
batch: list[type[Metric]] = [metric_cls]
|
|
@@ -160,6 +169,17 @@ class MetricCalculator:
|
|
|
160
169
|
i += 1
|
|
161
170
|
continue
|
|
162
171
|
|
|
172
|
+
failed_deps = self._get_failed_providers(
|
|
173
|
+
next_cls, failed_providers, failed
|
|
174
|
+
)
|
|
175
|
+
if failed_deps:
|
|
176
|
+
metric = self._create_failed_metric(next_cls, tags, failed_deps)
|
|
177
|
+
calculated[next_cls] = metric
|
|
178
|
+
result_metrics.append(metric)
|
|
179
|
+
failed.add(next_cls)
|
|
180
|
+
i += 1
|
|
181
|
+
continue
|
|
182
|
+
|
|
163
183
|
if next_cls.executor != current_executor:
|
|
164
184
|
break # Different executor, start new batch
|
|
165
185
|
|
|
@@ -192,9 +212,10 @@ class MetricCalculator:
|
|
|
192
212
|
)
|
|
193
213
|
|
|
194
214
|
logger.info(
|
|
195
|
-
"Metric calculation complete: %d calculated, %d skipped",
|
|
196
|
-
len(result_metrics),
|
|
215
|
+
"Metric calculation complete: %d calculated, %d skipped, %d failed",
|
|
216
|
+
len(result_metrics) - len(failed),
|
|
197
217
|
len(skipped),
|
|
218
|
+
len(failed),
|
|
198
219
|
)
|
|
199
220
|
return result_metrics
|
|
200
221
|
|
|
@@ -234,6 +255,63 @@ class MetricCalculator:
|
|
|
234
255
|
|
|
235
256
|
return False
|
|
236
257
|
|
|
258
|
+
def _get_failed_providers(
|
|
259
|
+
self,
|
|
260
|
+
metric_cls: type[Metric],
|
|
261
|
+
failed_providers: dict[type[Provider], ProviderError],
|
|
262
|
+
failed_metrics: set[type[Metric]],
|
|
263
|
+
) -> list[str]:
|
|
264
|
+
"""Get list of failed provider/metric names that this metric depends on.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
metric_cls: Metric class to check
|
|
268
|
+
failed_providers: Dict of failed provider classes to errors
|
|
269
|
+
failed_metrics: Set of metrics that failed due to provider errors
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
List of failed provider/metric names, empty if none
|
|
273
|
+
"""
|
|
274
|
+
failed_names = []
|
|
275
|
+
|
|
276
|
+
# Check direct provider dependencies
|
|
277
|
+
for provider_cls in metric_cls.providers():
|
|
278
|
+
if provider_cls in failed_providers:
|
|
279
|
+
failed_names.append(f"provider '{provider_cls.name}'")
|
|
280
|
+
|
|
281
|
+
# Check metric dependencies that failed
|
|
282
|
+
for dep_cls in metric_cls.depends_on():
|
|
283
|
+
if dep_cls in failed_metrics:
|
|
284
|
+
failed_names.append(f"metric '{dep_cls.name}'")
|
|
285
|
+
|
|
286
|
+
return failed_names
|
|
287
|
+
|
|
288
|
+
def _create_failed_metric(
|
|
289
|
+
self,
|
|
290
|
+
metric_cls: type[Metric],
|
|
291
|
+
tags: dict[str, Any],
|
|
292
|
+
failed_deps: list[str],
|
|
293
|
+
) -> Metric:
|
|
294
|
+
"""Create a metric instance with null value due to failed dependencies.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
metric_cls: Metric class to instantiate
|
|
298
|
+
tags: Tags to merge into the metric
|
|
299
|
+
failed_deps: List of failed dependency names
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Metric instance with value=None and diagnostic explaining failure
|
|
303
|
+
"""
|
|
304
|
+
metric = metric_cls(**self._configs.get(metric_cls.name, {}))
|
|
305
|
+
metric.tags.update(tags)
|
|
306
|
+
metric.value = None
|
|
307
|
+
metric.diagnostic = f"Failed: {', '.join(failed_deps)} failed"
|
|
308
|
+
logger.debug(
|
|
309
|
+
"Metric %s marked as failed: %s",
|
|
310
|
+
metric_cls.name,
|
|
311
|
+
metric.diagnostic,
|
|
312
|
+
)
|
|
313
|
+
return metric
|
|
314
|
+
|
|
237
315
|
def _execute_batch(
|
|
238
316
|
self,
|
|
239
317
|
batch: list[type[Metric]],
|
|
@@ -73,10 +73,14 @@ def _measure_single_provider_set(
|
|
|
73
73
|
Raises:
|
|
74
74
|
ProviderError: If a provider fails during execution
|
|
75
75
|
"""
|
|
76
|
-
context, tags, errors = ProviderExecutor().execute(provider_set
|
|
77
|
-
|
|
76
|
+
context, tags, errors = ProviderExecutor().execute(provider_set)
|
|
77
|
+
failed_providers = {type(e.provider): e for e in errors}
|
|
78
78
|
return MetricCalculator(metric_configs).calculate(
|
|
79
|
-
execution_order,
|
|
79
|
+
execution_order,
|
|
80
|
+
context,
|
|
81
|
+
tags,
|
|
82
|
+
{type(p) for p in provider_set},
|
|
83
|
+
failed_providers,
|
|
80
84
|
)
|
|
81
85
|
|
|
82
86
|
|
|
@@ -194,11 +198,30 @@ class CheckHub:
|
|
|
194
198
|
logger.debug("Provider set failure details:", exc_info=True)
|
|
195
199
|
all_errors.append((ps, e))
|
|
196
200
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
if all_errors:
|
|
202
|
+
failed_contexts = []
|
|
203
|
+
for ps, _ in all_errors:
|
|
204
|
+
tags = {
|
|
205
|
+
k: v
|
|
206
|
+
for p in ps
|
|
207
|
+
if p.is_tag_provider()
|
|
208
|
+
for k, v in p.provide().items()
|
|
209
|
+
}
|
|
210
|
+
failed_contexts.append(
|
|
211
|
+
tags if tags else {"providers": [p.name for p in ps]}
|
|
212
|
+
)
|
|
213
|
+
failed_contexts_str = "\n ".join(str(ctx) for ctx in failed_contexts)
|
|
214
|
+
logger.info(
|
|
215
|
+
"Measurement complete: %d metrics calculated, %d failed contexts:\n %s",
|
|
216
|
+
len(all_metrics),
|
|
217
|
+
len(all_errors),
|
|
218
|
+
failed_contexts_str,
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
logger.info(
|
|
222
|
+
"Measurement complete: %d metrics calculated",
|
|
223
|
+
len(all_metrics),
|
|
224
|
+
)
|
|
202
225
|
return MeasurementResult(
|
|
203
226
|
metrics=all_metrics,
|
|
204
227
|
direct_metric_names=direct_metric_names,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|