testsAndMisc/python_pkg/vscode_optimizer/_hardware.py
Krzysztof kuhy Rudnicki adf2e402df Grade against 3.14 too, not just run on it
`requires-python` and the CI pin already said 3.14, but ruff, mypy and pylint
were still grading `meta/` against 3.10 -- three tools judging an interpreter
nothing runs any more, and ruff withholding the pyupgrade fixes that only
become safe at the newer target. `pin_ci_python.py` rewrites these three knobs.

What the stale target was hiding: `datetime.timezone.utc` where `datetime.UTC`
is now correct (UP017), and ruff's stable formatter applying PEP 758 --
`except (A, B):` becomes `except A, B:`. That makes the source 3.14-only at the
syntax level, which is what `requires-python = ">=3.14"` already promised; kuhy
chose it deliberately over holding ruff a release back (2026-08-29).

Also drops a comment in `wsg_grabber/models.py` that the bump makes false: it
explained why the file used ``str, Enum`` instead of ``StrEnum`` under mypy at
3.10, sitting directly above a ``class Verdict(StrEnum)`` that had already
stopped obeying it.

ruff, ruff-format, mypy --strict and pylint all clean at the new target.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
2026-08-29 11:50:39 +02:00

111 lines
3.2 KiB
Python

"""Probe the machine's CPU, RAM, GPU, and root disk.
Every probe shells out and degrades to a default rather than raising, so a
missing tool narrows the report instead of failing the run.
"""
from __future__ import annotations
from pathlib import Path
import re
import subprocess
from python_pkg.vscode_optimizer._types import _Hw
_MIB_1024 = 1024
_LSCPU = {
"Model name": "cpu_model",
"CPU(s)": "cpu_logical_cores",
"Core(s) per socket": "cpu_physical_cores",
"CPU max MHz": "cpu_max_mhz",
}
_VENDOR_KW = {"nvidia": "NVIDIA", "amd": "AMD", "ati": "AMD", "intel": "Intel"}
def _run(args: list[str]) -> str:
"""Run *args* and return stdout, or ``""`` on failure."""
try:
proc = subprocess.run(
args,
capture_output=True,
text=True,
timeout=10,
check=False,
)
except subprocess.TimeoutExpired, FileNotFoundError:
return ""
return proc.stdout.strip()
def _detect_cpu(hw: _Hw) -> None:
for line in _run(["lscpu"]).splitlines():
key, _, val = line.partition(":")
attr = _LSCPU.get(key.strip())
if attr == "cpu_model":
hw.cpu_model = val.strip()
elif attr == "cpu_max_mhz":
hw.cpu_max_mhz = float(val)
elif attr is not None:
setattr(hw, attr, int(val))
def _detect_ram(hw: _Hw) -> None:
try:
meminfo = Path("/proc/meminfo").read_text(encoding="utf-8")
except OSError:
return
m = re.search(r"MemTotal:\s+(\d+)\s+kB", meminfo)
if m:
hw.ram_total_mb = int(m.group(1)) // _MIB_1024
def _detect_gpu(hw: _Hw) -> None:
for line in _run(["lspci"]).splitlines():
low = line.lower()
if "vga" not in low and "3d" not in low:
continue
hw.gpu_model = line.rsplit(":", maxsplit=1)[-1].strip()
# Match the device description only. The full line always contains
# "VGA compATIble controller", so matching *low* lets "ati" fire on
# every display device and hides every vendor checked after it.
model_low = hw.gpu_model.lower()
for kw, vendor in _VENDOR_KW.items():
if kw in model_low:
hw.gpu_vendor = vendor
break
if hw.gpu_vendor == "NVIDIA":
vram = _run(
[
"nvidia-smi",
"--query-gpu=memory.total",
"--format=csv,noheader,nounits",
]
)
if vram:
hw.gpu_vram_mb = int(vram.split("\n")[0].strip())
break
def _detect_disk(hw: _Hw) -> None:
root_dev = _run(["findmnt", "-n", "-o", "SOURCE", "/"])
if not root_dev:
return
base = re.sub(r"p?\d+$", "", Path(root_dev).name)
rotational = Path(f"/sys/block/{base}/queue/rotational")
if not rotational.exists():
return
if rotational.read_text(encoding="utf-8").strip() == "1":
hw.disk_type = "hdd"
elif "nvme" in base:
hw.disk_type = "nvme"
else:
hw.disk_type = "ssd"
def _detect_hardware() -> _Hw:
"""Probe CPU, RAM, GPU, and root disk type."""
hw = _Hw()
for fn in (_detect_cpu, _detect_ram, _detect_gpu, _detect_disk):
fn(hw)
return hw