checkup 0.5.1__tar.gz → 0.5.3__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.5.1 → checkup-0.5.3}/PKG-INFO +13 -5
- {checkup-0.5.1 → checkup-0.5.3}/README.md +9 -4
- {checkup-0.5.1 → checkup-0.5.3}/pyproject.toml +6 -1
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/commands/run.py +12 -1
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/executor.py +12 -2
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/executor/metric_calculator.py +15 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/hub.py +48 -22
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/commands/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/commands/config.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/commands/init.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/commands/plugins.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/commands/schema.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/config_wizard/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/config_wizard/_common.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/config_wizard/create.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/config_wizard/edit.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/cli/utils.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/config.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/configuration/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/configuration/env.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/configuration/io.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/configuration/models.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/configuration/schema.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/errors.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/executor/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/executor/batch_executors.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/executor/provider_executor.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/executor/state.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/graph.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/materializers/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/materializers/base.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/materializers/console.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/materializers/csv_file.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/materializers/database.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/materializers/html_report.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/measurement.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/metric.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/provider.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/providers/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/providers/tags.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/registry/__init__.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/registry/discovery.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/templates/metrics_report.html +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/types.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/utils.py +0 -0
- {checkup-0.5.1 → checkup-0.5.3}/src/checkup/validators.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: checkup
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: Computational governance framework for measuring data product health
|
|
5
5
|
Author: Jan Vanbuel
|
|
6
6
|
Author-email: Jan Vanbuel <jan.vanbuel@ond.vlaanderen.be>
|
|
@@ -15,14 +15,22 @@ Requires-Dist: rich>=13.0
|
|
|
15
15
|
Requires-Dist: sqlalchemy>=2.0
|
|
16
16
|
Requires-Dist: typer>=0.24
|
|
17
17
|
Requires-Python: >=3.12
|
|
18
|
+
Project-URL: Homepage, https://github.com/datamindedbe/checkup
|
|
19
|
+
Project-URL: Issues, https://github.com/datamindedbe/checkup/issues
|
|
20
|
+
Project-URL: Source, https://github.com/datamindedbe/checkup
|
|
18
21
|
Description-Content-Type: text/markdown
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="https://raw.githubusercontent.com/datamindedbe/checkup/main/assets/banner.png" alt="CheckUp" width="100%" />
|
|
25
|
+
</p>
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
<h3 align="center">Computational Governance Framework</h3>
|
|
28
|
+
<p align="center">for measuring <b>data product health</b></p>
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="https://pypi.org/project/checkup/"><img src="https://img.shields.io/pypi/v/checkup" alt="PyPI version" /></a>
|
|
32
|
+
<a href="https://pypi.org/project/checkup/"><img src="https://img.shields.io/pypi/pyversions/checkup" alt="Python versions" /></a>
|
|
33
|
+
</p>
|
|
26
34
|
|
|
27
35
|
## Plugins
|
|
28
36
|
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/datamindedbe/checkup/main/assets/banner.png" alt="CheckUp" width="100%" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
<h3 align="center">Computational Governance Framework</h3>
|
|
6
|
+
<p align="center">for measuring <b>data product health</b></p>
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://pypi.org/project/checkup/"><img src="https://img.shields.io/pypi/v/checkup" alt="PyPI version" /></a>
|
|
10
|
+
<a href="https://pypi.org/project/checkup/"><img src="https://img.shields.io/pypi/pyversions/checkup" alt="Python versions" /></a>
|
|
11
|
+
</p>
|
|
7
12
|
|
|
8
13
|
## Plugins
|
|
9
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "checkup"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.3"
|
|
4
4
|
description = "Computational governance framework for measuring data product health"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Jan Vanbuel", email = "jan.vanbuel@ond.vlaanderen.be" }]
|
|
@@ -20,6 +20,11 @@ dependencies = [
|
|
|
20
20
|
"typer>=0.24",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://github.com/datamindedbe/checkup"
|
|
25
|
+
Source = "https://github.com/datamindedbe/checkup"
|
|
26
|
+
Issues = "https://github.com/datamindedbe/checkup/issues"
|
|
27
|
+
|
|
23
28
|
[project.scripts]
|
|
24
29
|
checkup = "checkup:main"
|
|
25
30
|
|
|
@@ -40,6 +40,13 @@ def run(
|
|
|
40
40
|
bool,
|
|
41
41
|
typer.Option("--dry-run", help="Don't materialize, just print"),
|
|
42
42
|
] = False,
|
|
43
|
+
multiprocessing: Annotated[
|
|
44
|
+
bool,
|
|
45
|
+
typer.Option(
|
|
46
|
+
"--multiprocessing/--no-multiprocessing",
|
|
47
|
+
help="Use multiprocessing. Disable with --no-multiprocessing to run sequentially without subprocesses",
|
|
48
|
+
),
|
|
49
|
+
] = True,
|
|
43
50
|
verbose: Annotated[
|
|
44
51
|
bool,
|
|
45
52
|
typer.Option("--verbose", "-v", help="Verbose output"),
|
|
@@ -55,4 +62,8 @@ def run(
|
|
|
55
62
|
cfg = load_config(config_path=config)
|
|
56
63
|
cfg = apply_cli_overrides(cfg, tag, provider, metric)
|
|
57
64
|
|
|
58
|
-
execute_checkup(
|
|
65
|
+
execute_checkup(
|
|
66
|
+
cfg,
|
|
67
|
+
materializer="console" if dry_run else materializer,
|
|
68
|
+
multiprocessing=multiprocessing,
|
|
69
|
+
)
|
|
@@ -23,13 +23,18 @@ logger = logging.getLogger(__name__)
|
|
|
23
23
|
console = Console()
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def execute_checkup(
|
|
26
|
+
def execute_checkup(
|
|
27
|
+
config: CheckupConfig,
|
|
28
|
+
materializer: str | None = None,
|
|
29
|
+
multiprocessing: bool = True,
|
|
30
|
+
) -> None:
|
|
27
31
|
"""
|
|
28
32
|
Execute checkup with the given configuration.
|
|
29
33
|
|
|
30
34
|
Args:
|
|
31
35
|
config: Loaded checkup configuration
|
|
32
36
|
materializer: Override materializer type (e.g., "console")
|
|
37
|
+
multiprocessing: If False, run sequentially without subprocesses
|
|
33
38
|
"""
|
|
34
39
|
|
|
35
40
|
registry = get_registry()
|
|
@@ -48,7 +53,12 @@ def execute_checkup(config: CheckupConfig, materializer: str | None = None) -> N
|
|
|
48
53
|
|
|
49
54
|
console.print(f"[blue]Running {len(metrics)} metrics...[/blue]")
|
|
50
55
|
|
|
51
|
-
result =
|
|
56
|
+
result = (
|
|
57
|
+
CheckHub()
|
|
58
|
+
.with_metrics(metrics)
|
|
59
|
+
.with_providers([providers])
|
|
60
|
+
.measure(multiprocessing=multiprocessing)
|
|
61
|
+
)
|
|
52
62
|
|
|
53
63
|
if result.errors:
|
|
54
64
|
for _, error in result.errors:
|
|
@@ -37,6 +37,15 @@ class MetricCalculator:
|
|
|
37
37
|
Calculates metrics for a given context.
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
|
+
def __init__(self, multiprocessing: bool = True) -> None:
|
|
41
|
+
"""
|
|
42
|
+
Args:
|
|
43
|
+
multiprocessing: If False, metrics that request the PROCESS executor are run with the THREAD executor instead.
|
|
44
|
+
This avoids spawning subprocesses in environments that do not support it.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
self._multiprocessing = multiprocessing
|
|
48
|
+
|
|
40
49
|
def calculate(
|
|
41
50
|
self,
|
|
42
51
|
metrics: list[Metric],
|
|
@@ -193,6 +202,12 @@ class MetricCalculator:
|
|
|
193
202
|
Execute a batch and record results.
|
|
194
203
|
"""
|
|
195
204
|
|
|
205
|
+
if not self._multiprocessing and executor_type is ExecutorType.PROCESS:
|
|
206
|
+
logger.debug(
|
|
207
|
+
"No subprocesses requested: running PROCESS batch with THREAD executor"
|
|
208
|
+
)
|
|
209
|
+
executor_type = ExecutorType.THREAD
|
|
210
|
+
|
|
196
211
|
logger.debug(
|
|
197
212
|
"Executing batch with %d metrics using %s executor",
|
|
198
213
|
len(batch),
|
|
@@ -57,6 +57,7 @@ def _measure_single_provider_set(
|
|
|
57
57
|
provider_set: list[Provider],
|
|
58
58
|
metrics: list[Metric],
|
|
59
59
|
execution_order: list[type[Metric]],
|
|
60
|
+
multiprocessing: bool = True,
|
|
60
61
|
) -> list[Measurement]:
|
|
61
62
|
"""Calculate all metrics for a single provider set.
|
|
62
63
|
|
|
@@ -66,6 +67,7 @@ def _measure_single_provider_set(
|
|
|
66
67
|
provider_set: List of provider instances
|
|
67
68
|
metrics: List of metric instances to calculate
|
|
68
69
|
execution_order: Topologically sorted metric classes
|
|
70
|
+
multiprocessing: If False, run metric batches without subprocesses
|
|
69
71
|
|
|
70
72
|
Returns:
|
|
71
73
|
List of Measurements with tags merged
|
|
@@ -77,7 +79,7 @@ def _measure_single_provider_set(
|
|
|
77
79
|
context, errors = ProviderExecutor().execute(provider_set)
|
|
78
80
|
failed_providers = {type(e.provider): e for e in errors}
|
|
79
81
|
|
|
80
|
-
return MetricCalculator().calculate(
|
|
82
|
+
return MetricCalculator(multiprocessing=multiprocessing).calculate(
|
|
81
83
|
metrics,
|
|
82
84
|
execution_order,
|
|
83
85
|
context,
|
|
@@ -133,11 +135,17 @@ class CheckHub:
|
|
|
133
135
|
def measure(
|
|
134
136
|
self,
|
|
135
137
|
max_workers: int | None = None,
|
|
138
|
+
multiprocessing: bool = True,
|
|
136
139
|
) -> MeasurementResult:
|
|
137
|
-
"""
|
|
140
|
+
"""
|
|
141
|
+
Execute the measurement pipeline.
|
|
138
142
|
|
|
139
143
|
Args:
|
|
140
144
|
max_workers: Max parallel workers. None = use all CPUs.
|
|
145
|
+
Ignored when multiprocessing=False.
|
|
146
|
+
multiprocessing: If True, provider sets run in parallel via ProcessPoolExecutor.
|
|
147
|
+
If False, provider sets run sequentially and
|
|
148
|
+
metrics requesting the PROCESS executor fall back to threads.
|
|
141
149
|
|
|
142
150
|
Returns:
|
|
143
151
|
MeasurementResult containing all calculated measurements and errors
|
|
@@ -161,28 +169,46 @@ class CheckHub:
|
|
|
161
169
|
|
|
162
170
|
all_measurements: list[Measurement] = []
|
|
163
171
|
all_errors: list[tuple[list[Provider], Exception]] = []
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
172
|
+
|
|
173
|
+
def _record(ps: list[Provider], e: Exception) -> None:
|
|
174
|
+
logger.error("Provider set failed: %s", e)
|
|
175
|
+
logger.debug("Provider set failure details:", exc_info=True)
|
|
176
|
+
all_errors.append((ps, e))
|
|
177
|
+
|
|
178
|
+
if multiprocessing:
|
|
179
|
+
workers = max_workers if max_workers is not None else os.cpu_count()
|
|
180
|
+
logger.debug("Executing with %d workers", workers)
|
|
181
|
+
with ProcessPoolExecutor(max_workers=workers) as executor:
|
|
182
|
+
future_to_provider_set = {
|
|
183
|
+
executor.submit(
|
|
184
|
+
_measure_single_provider_set,
|
|
185
|
+
provider_set=ps,
|
|
186
|
+
metrics=self._metrics,
|
|
187
|
+
execution_order=execution_order,
|
|
188
|
+
): ps
|
|
189
|
+
for ps in provider_sets
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for future in as_completed(future_to_provider_set):
|
|
193
|
+
ps = future_to_provider_set[future]
|
|
194
|
+
try:
|
|
195
|
+
all_measurements.extend(future.result())
|
|
196
|
+
except Exception as e:
|
|
197
|
+
_record(ps, e)
|
|
198
|
+
else:
|
|
199
|
+
logger.debug("Executing sequentially")
|
|
200
|
+
for ps in provider_sets:
|
|
180
201
|
try:
|
|
181
|
-
all_measurements.extend(
|
|
202
|
+
all_measurements.extend(
|
|
203
|
+
_measure_single_provider_set(
|
|
204
|
+
provider_set=ps,
|
|
205
|
+
metrics=self._metrics,
|
|
206
|
+
execution_order=execution_order,
|
|
207
|
+
multiprocessing=False,
|
|
208
|
+
)
|
|
209
|
+
)
|
|
182
210
|
except Exception as e:
|
|
183
|
-
|
|
184
|
-
logger.debug("Provider set failure details:", exc_info=True)
|
|
185
|
-
all_errors.append((ps, e))
|
|
211
|
+
_record(ps, e)
|
|
186
212
|
|
|
187
213
|
if all_errors:
|
|
188
214
|
failed_contexts = []
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|