Skill Tracer
Skills › Scientific Agent Skills › markitdown › inspect_installation.py

inspect_installation.py

162 lines · skills/markitdown/scripts/inspect_installation.py at 5f2bc03

1#!/usr/bin/env python3
2"""Inspect a MarkItDown installation without loading plugins or using network."""
3
4from __future__ import annotations
5
6import argparse
7import json
8import platform
9import shutil
10from importlib.metadata import (
11 PackageNotFoundError,
12 entry_points,
13 metadata,
14 version,
16from typing import Any
19TARGET_VERSION = "0.1.8"
20OPTIONAL_DISTRIBUTIONS = (
21 "markitdown-ocr",
22 "markitdown-mcp",
23 "openai",
24 "azure-ai-documentintelligence",
25 "azure-ai-contentunderstanding",
29def distribution_version(name: str) -> str | None:
30 """Return an installed distribution version without importing it."""
31 try:
32 return version(name)
33 except PackageNotFoundError:
34 return None
37def inspect_installation() -> dict[str, Any]:
38 """Collect package, extra, plugin, and executable metadata."""
39 try:
40 installed_version = version("markitdown")
41 package_metadata = metadata("markitdown")
42 extras = sorted(set(package_metadata.get_all("Provides-Extra") or []))
43 import_error = None
44 try:
45 from markitdown import MarkItDown # noqa: F401
46 except Exception as exc: # Report import health without hiding details.
47 import_error = f"{type(exc).__name__}: {exc}"
48 except PackageNotFoundError:
49 installed_version = None
50 extras = []
51 import_error = "PackageNotFoundError: markitdown is not installed"
53 discovered_plugins = sorted(
54 (
55 {
56 "name": point.name,
57 "module": point.value,
58 "distribution": (
59 point.dist.name
60 if getattr(point, "dist", None) is not None
61 else None
62 ),
63 }
64 for point in entry_points(group="markitdown.plugin")
65 ),
66 key=lambda item: (item["name"], item["module"]),
67 )
69 return {
70 "target_version": TARGET_VERSION,
71 "python": platform.python_version(),
72 "markitdown": {
73 "version": installed_version,
74 "import_error": import_error,
75 "declared_extras": extras,
76 },
77 "optional_distributions": {
78 name: distribution_version(name) for name in OPTIONAL_DISTRIBUTIONS
79 },
80 "plugins": discovered_plugins,
81 "executables": {
82 "markitdown": shutil.which("markitdown"),
83 "markitdown-mcp": shutil.which("markitdown-mcp"),
84 "exiftool": shutil.which("exiftool"),
85 "ffmpeg": shutil.which("ffmpeg"),
86 },
87 }
90def print_human_readable(report: dict[str, Any]) -> None:
91 markitdown = report["markitdown"]
92 print(f"Python: {report['python']}")
93 print(
94 "MarkItDown: "
95 f"{markitdown['version'] or 'not installed'} "
96 f"(skill target: {report['target_version']})"
97 )
98 if markitdown["import_error"]:
99 print(f"Import health: {markitdown['import_error']}")
100 else:
101 print("Import health: OK")
103 extras = markitdown["declared_extras"]
104 print(f"Declared extras: {', '.join(extras) if extras else 'unavailable'}")
106 print("Optional distributions:")
107 for name, installed_version in report["optional_distributions"].items():
108 print(f" {name}: {installed_version or 'not installed'}")
110 print("Discovered plugins (not loaded):")
111 if report["plugins"]:
112 for plugin in report["plugins"]:
113 distribution = plugin["distribution"] or "unknown distribution"
114 print(f" {plugin['name']}: {plugin['module']} ({distribution})")
115 else:
116 print(" none")
118 print("Executables:")
119 for name, path in report["executables"].items():
120 print(f" {name}: {path or 'not found'}")
123def build_parser() -> argparse.ArgumentParser:
124 parser = argparse.ArgumentParser(
125 description=(
126 "Inspect MarkItDown versions, extras, plugin entry points, and "
127 "optional executables without loading plugins."
128 )
129 )
130 parser.add_argument(
131 "--json",
132 action="store_true",
133 help="Print machine-readable JSON",
134 )
135 parser.add_argument(
136 "--allow-version-mismatch",
137 action="store_true",
138 help="Exit successfully when MarkItDown differs from the skill target",
139 )
140 return parser
143def main() -> int:
144 args = build_parser().parse_args()
145 report = inspect_installation()
147 if args.json:
148 print(json.dumps(report, indent=2, ensure_ascii=False))
149 else:
150 print_human_readable(report)
152 installed_version = report["markitdown"]["version"]
153 import_error = report["markitdown"]["import_error"]
154 if import_error is not None:
155 return 1
156 if installed_version != TARGET_VERSION and not args.allow_version_mismatch:
157 return 1
158 return 0
161if __name__ == "__main__":
162 raise SystemExit(main())