checkup 0.5.2__tar.gz → 0.6.0__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.2 → checkup-0.6.0}/PKG-INFO +10 -5
- {checkup-0.5.2 → checkup-0.6.0}/README.md +9 -4
- {checkup-0.5.2 → checkup-0.6.0}/pyproject.toml +2 -1
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/commands/run.py +7 -2
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/executor.py +20 -15
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/materializers/__init__.py +2 -0
- checkup-0.6.0/src/checkup/materializers/markdown.py +52 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/commands/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/commands/config.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/commands/init.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/commands/plugins.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/commands/schema.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/config_wizard/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/config_wizard/_common.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/config_wizard/create.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/config_wizard/edit.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/cli/utils.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/config.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/configuration/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/configuration/env.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/configuration/io.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/configuration/models.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/configuration/schema.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/errors.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/executor/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/executor/batch_executors.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/executor/metric_calculator.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/executor/provider_executor.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/executor/state.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/graph.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/hub.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/materializers/base.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/materializers/console.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/materializers/csv_file.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/materializers/database.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/materializers/html_report.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/measurement.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/metric.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/provider.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/providers/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/providers/tags.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/registry/__init__.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/registry/discovery.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/templates/metrics_report.html +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/types.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/utils.py +0 -0
- {checkup-0.5.2 → checkup-0.6.0}/src/checkup/validators.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: checkup
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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>
|
|
@@ -20,12 +20,17 @@ Project-URL: Issues, https://github.com/datamindedbe/checkup/issues
|
|
|
20
20
|
Project-URL: Source, https://github.com/datamindedbe/checkup
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="https://raw.githubusercontent.com/datamindedbe/checkup/main/assets/banner.png" alt="CheckUp" width="100%" />
|
|
25
|
+
</p>
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
<h3 align="center">Computational Governance Framework</h3>
|
|
28
|
+
<p align="center">for measuring <b>data product health</b></p>
|
|
27
29
|
|
|
28
|
-
|
|
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>
|
|
29
34
|
|
|
30
35
|
## Plugins
|
|
31
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.
|
|
3
|
+
version = "0.6.0"
|
|
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" }]
|
|
@@ -32,6 +32,7 @@ checkup = "checkup:main"
|
|
|
32
32
|
console = "checkup.materializers:ConsoleMaterializer"
|
|
33
33
|
csv = "checkup.materializers:CSVMaterializer"
|
|
34
34
|
html = "checkup.materializers:HTMLMaterializer"
|
|
35
|
+
markdown = "checkup.materializers:MarkdownMaterializer"
|
|
35
36
|
sqlalchemy = "checkup.materializers:SQLAlchemyMaterializer"
|
|
36
37
|
|
|
37
38
|
[build-system]
|
|
@@ -43,14 +43,18 @@ def run(
|
|
|
43
43
|
multiprocessing: Annotated[
|
|
44
44
|
bool,
|
|
45
45
|
typer.Option(
|
|
46
|
-
"--multiprocessing",
|
|
47
|
-
help="
|
|
46
|
+
"--multiprocessing/--no-multiprocessing",
|
|
47
|
+
help="Use multiprocessing. Disable with --no-multiprocessing to run sequentially without subprocesses",
|
|
48
48
|
),
|
|
49
49
|
] = True,
|
|
50
50
|
verbose: Annotated[
|
|
51
51
|
bool,
|
|
52
52
|
typer.Option("--verbose", "-v", help="Verbose output"),
|
|
53
53
|
] = False,
|
|
54
|
+
quiet: Annotated[
|
|
55
|
+
bool,
|
|
56
|
+
typer.Option("--quiet", "-q", help="Only print materializer output to stdout"),
|
|
57
|
+
] = False,
|
|
54
58
|
) -> None:
|
|
55
59
|
"""
|
|
56
60
|
Run metrics and materialize results.
|
|
@@ -66,4 +70,5 @@ def run(
|
|
|
66
70
|
cfg,
|
|
67
71
|
materializer="console" if dry_run else materializer,
|
|
68
72
|
multiprocessing=multiprocessing,
|
|
73
|
+
quiet=quiet,
|
|
69
74
|
)
|
|
@@ -27,6 +27,7 @@ def execute_checkup(
|
|
|
27
27
|
config: CheckupConfig,
|
|
28
28
|
materializer: str | None = None,
|
|
29
29
|
multiprocessing: bool = True,
|
|
30
|
+
quiet: bool = False,
|
|
30
31
|
) -> None:
|
|
31
32
|
"""
|
|
32
33
|
Execute checkup with the given configuration.
|
|
@@ -35,23 +36,26 @@ def execute_checkup(
|
|
|
35
36
|
config: Loaded checkup configuration
|
|
36
37
|
materializer: Override materializer type (e.g., "console")
|
|
37
38
|
multiprocessing: If False, run sequentially without subprocesses
|
|
39
|
+
quiet: If True, send status/errors to stderr so stdout holds only the materializer output.
|
|
38
40
|
"""
|
|
39
41
|
|
|
42
|
+
out = Console(stderr=True) if quiet else console
|
|
43
|
+
|
|
40
44
|
registry = get_registry()
|
|
41
45
|
|
|
42
|
-
providers = _resolve_providers(config, registry)
|
|
46
|
+
providers = _resolve_providers(config, registry, out)
|
|
43
47
|
if not providers:
|
|
44
|
-
|
|
48
|
+
out.print("[yellow]No providers configured[/yellow]")
|
|
45
49
|
return
|
|
46
50
|
|
|
47
|
-
metrics = _resolve_metrics(config, registry)
|
|
51
|
+
metrics = _resolve_metrics(config, registry, out)
|
|
48
52
|
if not metrics:
|
|
49
|
-
|
|
53
|
+
out.print("[yellow]No metrics configured[/yellow]")
|
|
50
54
|
return
|
|
51
55
|
|
|
52
|
-
materializer = _resolve_materializer(config, registry, materializer)
|
|
56
|
+
materializer = _resolve_materializer(config, registry, materializer, out)
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
out.print(f"[blue]Running {len(metrics)} metrics...[/blue]")
|
|
55
59
|
|
|
56
60
|
result = (
|
|
57
61
|
CheckHub()
|
|
@@ -62,7 +66,7 @@ def execute_checkup(
|
|
|
62
66
|
|
|
63
67
|
if result.errors:
|
|
64
68
|
for _, error in result.errors:
|
|
65
|
-
|
|
69
|
+
out.print(f"[red]Error: {error}[/red]")
|
|
66
70
|
|
|
67
71
|
result.materialize(materializer)
|
|
68
72
|
|
|
@@ -70,6 +74,7 @@ def execute_checkup(
|
|
|
70
74
|
def _resolve_providers(
|
|
71
75
|
config: CheckupConfig,
|
|
72
76
|
registry: "PluginRegistry",
|
|
77
|
+
out: Console = console,
|
|
73
78
|
) -> list["Provider"]:
|
|
74
79
|
"""
|
|
75
80
|
Resolve provider configs to provider instances.
|
|
@@ -83,14 +88,14 @@ def _resolve_providers(
|
|
|
83
88
|
for provider_config in config.providers:
|
|
84
89
|
provider_cls = registry.get_provider(provider_config.name)
|
|
85
90
|
if provider_cls is None:
|
|
86
|
-
|
|
91
|
+
out.print(f"[yellow]Unknown provider: {provider_config.name}[/yellow]")
|
|
87
92
|
continue
|
|
88
93
|
|
|
89
94
|
try:
|
|
90
95
|
provider = provider_cls(**provider_config.config)
|
|
91
96
|
providers.append(provider)
|
|
92
97
|
except Exception as e:
|
|
93
|
-
|
|
98
|
+
out.print(
|
|
94
99
|
f"[red]Failed to instantiate provider {provider_config.name}: {e}[/red]"
|
|
95
100
|
)
|
|
96
101
|
|
|
@@ -100,6 +105,7 @@ def _resolve_providers(
|
|
|
100
105
|
def _resolve_metrics(
|
|
101
106
|
config: CheckupConfig,
|
|
102
107
|
registry: "PluginRegistry",
|
|
108
|
+
out: Console = console,
|
|
103
109
|
) -> list["Metric"]:
|
|
104
110
|
"""
|
|
105
111
|
Resolve metric configs to metric instances.
|
|
@@ -110,7 +116,7 @@ def _resolve_metrics(
|
|
|
110
116
|
for metric_config in config.metrics:
|
|
111
117
|
metric_cls = registry.get_metric(metric_config.type)
|
|
112
118
|
if metric_cls is None:
|
|
113
|
-
|
|
119
|
+
out.print(f"[yellow]Unknown metric: {metric_config.type}[/yellow]")
|
|
114
120
|
continue
|
|
115
121
|
|
|
116
122
|
try:
|
|
@@ -121,7 +127,7 @@ def _resolve_metrics(
|
|
|
121
127
|
)
|
|
122
128
|
)
|
|
123
129
|
except Exception as e:
|
|
124
|
-
|
|
130
|
+
out.print(
|
|
125
131
|
f"[red]Failed to instantiate metric {metric_config.type}: {e}[/red]"
|
|
126
132
|
)
|
|
127
133
|
|
|
@@ -132,6 +138,7 @@ def _resolve_materializer(
|
|
|
132
138
|
config: CheckupConfig,
|
|
133
139
|
registry: "PluginRegistry",
|
|
134
140
|
override: str | None = None,
|
|
141
|
+
out: Console = console,
|
|
135
142
|
) -> "Materializer":
|
|
136
143
|
"""
|
|
137
144
|
Resolve materializer config to materializer instance.
|
|
@@ -150,13 +157,11 @@ def _resolve_materializer(
|
|
|
150
157
|
materializer_cls = registry.get_materializer(mat_type)
|
|
151
158
|
|
|
152
159
|
if materializer_cls is None:
|
|
153
|
-
|
|
154
|
-
f"[yellow]Unknown materializer: {mat_type}, using console[/yellow]"
|
|
155
|
-
)
|
|
160
|
+
out.print(f"[yellow]Unknown materializer: {mat_type}, using console[/yellow]")
|
|
156
161
|
return ConsoleMaterializer()
|
|
157
162
|
|
|
158
163
|
try:
|
|
159
164
|
return materializer_cls(**mat_config)
|
|
160
165
|
except Exception as e:
|
|
161
|
-
|
|
166
|
+
out.print(f"[red]Failed to instantiate materializer {mat_type}: {e}[/red]")
|
|
162
167
|
return ConsoleMaterializer()
|
|
@@ -9,11 +9,13 @@ from checkup.materializers.console import ConsoleMaterializer
|
|
|
9
9
|
from checkup.materializers.csv_file import CSVMaterializer
|
|
10
10
|
from checkup.materializers.database import SQLAlchemyMaterializer
|
|
11
11
|
from checkup.materializers.html_report import HTMLMaterializer
|
|
12
|
+
from checkup.materializers.markdown import MarkdownMaterializer
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
"ConsoleMaterializer",
|
|
15
16
|
"CSVMaterializer",
|
|
16
17
|
"HTMLMaterializer",
|
|
18
|
+
"MarkdownMaterializer",
|
|
17
19
|
"Materializer",
|
|
18
20
|
"SQLAlchemyMaterializer",
|
|
19
21
|
"group_measurements_by_tags",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Markdown materializer for Markdown table output."""
|
|
2
|
+
|
|
3
|
+
from checkup.materializers.base import Materializer
|
|
4
|
+
from checkup.measurement import Measurement
|
|
5
|
+
|
|
6
|
+
COLUMNS = ("Name", "Description", "Value", "Unit", "Diagnostics")
|
|
7
|
+
ALIGNMENTS = ("---", "---", "---:", "---", "---") # Right-align the Value column.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MarkdownMaterializer(Materializer):
|
|
11
|
+
"""
|
|
12
|
+
Output measurements as a GitHub-flavoured Markdown table.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def materialize(
|
|
16
|
+
self, measurements: list[Measurement], direct_metric_names: set[str]
|
|
17
|
+
) -> None:
|
|
18
|
+
"""
|
|
19
|
+
Print measurements as a Markdown table.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
filtered = self._filter_measurements(measurements, direct_metric_names)
|
|
23
|
+
|
|
24
|
+
rows = [self._row(COLUMNS), self._row(ALIGNMENTS)]
|
|
25
|
+
for measurement in filtered:
|
|
26
|
+
rows.append(
|
|
27
|
+
self._row(
|
|
28
|
+
(
|
|
29
|
+
measurement.metric.name,
|
|
30
|
+
measurement.metric.description,
|
|
31
|
+
str(measurement.value) if measurement.value is not None else "",
|
|
32
|
+
measurement.metric.unit,
|
|
33
|
+
measurement.diagnostic,
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
print("\n".join(rows))
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def _row(cls, cells: tuple[str, ...]) -> str:
|
|
41
|
+
return "| " + " | ".join(cls._cell(cell) for cell in cells) + " |"
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def _cell(value: str) -> str:
|
|
45
|
+
"""
|
|
46
|
+
Escape a value for a Markdown table cell.
|
|
47
|
+
|
|
48
|
+
Cells cannot contain a raw pipe (column separator) or newline (row separator),
|
|
49
|
+
so escape pipes and turn newlines into `<br>`.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
return str(value or "").replace("|", "\\|").replace("\n", "<br>").strip()
|
|
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
|
|
File without changes
|