Coverage for src/duty/debug.py: 91.78%
63 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-17 17:18 +0200
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-17 17:18 +0200
1"""Debugging utilities."""
3from __future__ import annotations
5import os
6import platform
7import sys
8from dataclasses import dataclass
9from importlib import metadata
12@dataclass
13class Variable:
14 """Dataclass describing an environment variable."""
16 name: str
17 """Variable name."""
18 value: str
19 """Variable value."""
22@dataclass
23class Package:
24 """Dataclass describing a Python package."""
26 name: str
27 """Package name."""
28 version: str
29 """Package version."""
32@dataclass
33class Environment:
34 """Dataclass to store environment information."""
36 interpreter_name: str
37 """Python interpreter name."""
38 interpreter_version: str
39 """Python interpreter version."""
40 interpreter_path: str
41 """Path to Python executable."""
42 platform: str
43 """Operating System."""
44 packages: list[Package]
45 """Installed packages."""
46 variables: list[Variable]
47 """Environment variables."""
50def _interpreter_name_version() -> tuple[str, str]:
51 if hasattr(sys, "implementation"): 51 ↛ 58line 51 didn't jump to line 58 because the condition on line 51 was always true
52 impl = sys.implementation.version
53 version = f"{impl.major}.{impl.minor}.{impl.micro}"
54 kind = impl.releaselevel
55 if kind != "final":
56 version += kind[0] + str(impl.serial)
57 return sys.implementation.name, version
58 return "", "0.0.0"
61def get_version(dist: str = "duty") -> str:
62 """Get version of the given distribution.
64 Parameters:
65 dist: A distribution name.
67 Returns:
68 A version number.
69 """
70 try:
71 return metadata.version(dist)
72 except metadata.PackageNotFoundError:
73 return "0.0.0"
76def get_debug_info() -> Environment:
77 """Get debug/environment information.
79 Returns:
80 Environment information.
81 """
82 py_name, py_version = _interpreter_name_version()
83 packages = ["duty"]
84 variables = ["PYTHONPATH", *[var for var in os.environ if var.startswith("DUTY")]]
85 return Environment(
86 interpreter_name=py_name,
87 interpreter_version=py_version,
88 interpreter_path=sys.executable,
89 platform=platform.platform(),
90 variables=[Variable(var, val) for var in variables if (val := os.getenv(var))],
91 packages=[Package(pkg, get_version(pkg)) for pkg in packages],
92 )
95def print_debug_info() -> None:
96 """Print debug/environment information."""
97 info = get_debug_info()
98 print(f"- __System__: {info.platform}")
99 print(f"- __Python__: {info.interpreter_name} {info.interpreter_version} ({info.interpreter_path})")
100 print("- __Environment variables__:")
101 for var in info.variables:
102 print(f" - `{var.name}`: `{var.value}`")
103 print("- __Installed packages__:")
104 for pkg in info.packages:
105 print(f" - `{pkg.name}` v{pkg.version}")
108if __name__ == "__main__": 108 ↛ 109line 108 didn't jump to line 109 because the condition on line 108 was never true
109 print_debug_info()