mirror of
https://github.com/HorlogeSkynet/archey4
synced 2024-11-24 04:00:10 +01:00
923990c3c6
Replaces callback with property
96 lines
3.4 KiB
Python
96 lines
3.4 KiB
Python
"""GPU information detection class"""
|
|
|
|
import platform
|
|
import re
|
|
from functools import cached_property
|
|
from subprocess import DEVNULL, CalledProcessError, check_output
|
|
from typing import List
|
|
|
|
from archey.entry import Entry
|
|
|
|
|
|
class GPU(Entry):
|
|
"""Relies on `lspci` or `pciconf` to retrieve graphical device(s) information"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if platform.system() == "Linux":
|
|
self.value = self._parse_lspci_output()
|
|
else:
|
|
# Darwin or any other BSD-based system.
|
|
self.value = self._parse_system_profiler() or self._parse_pciconf_output()
|
|
|
|
max_count = self.options.get("max_count", 2)
|
|
# Consistency with other entries' configuration: Infinite count if false.
|
|
if max_count is not False:
|
|
self.value = self.value[:max_count]
|
|
|
|
@staticmethod
|
|
def _parse_lspci_output() -> List[str]:
|
|
"""Based on `lspci` output, return a list of video controllers names"""
|
|
try:
|
|
lspci_output = check_output("lspci", universal_newlines=True).splitlines()
|
|
except (FileNotFoundError, CalledProcessError):
|
|
return []
|
|
|
|
gpus_list = []
|
|
|
|
# We'll be looking for specific video controllers (in the below keys order).
|
|
for video_key in ("3D", "VGA", "Display"):
|
|
for pci_device in lspci_output:
|
|
# If a controller type match...
|
|
if video_key in pci_device:
|
|
# ... adds its name to the final list.
|
|
gpus_list.append(pci_device.partition(": ")[2])
|
|
|
|
return gpus_list
|
|
|
|
@staticmethod
|
|
def _parse_system_profiler() -> List[str]:
|
|
"""Based on `system_profiler` output, return a list of video chipsets model names"""
|
|
# Parse output from Darwin's `system_profiler` binary.
|
|
# We do not use JSON output (more than 10 times longer for nothing).
|
|
try:
|
|
profiler_output = check_output(
|
|
["system_profiler", "SPDisplaysDataType"], stderr=DEVNULL, universal_newlines=True
|
|
)
|
|
except FileNotFoundError:
|
|
return []
|
|
|
|
return re.findall(r"Chipset Model: (.*)", profiler_output, re.MULTILINE)
|
|
|
|
@staticmethod
|
|
def _parse_pciconf_output() -> List[str]:
|
|
"""Based on `pciconf` output, return a list of video devices as long as their vendor"""
|
|
try:
|
|
pciconf_output = check_output(
|
|
["pciconf", "-lv"], stderr=DEVNULL, universal_newlines=True
|
|
)
|
|
except (FileNotFoundError, CalledProcessError):
|
|
return []
|
|
|
|
gpus_list = []
|
|
|
|
for vendor, device in re.findall(
|
|
r"vendor\s*=\s*\'(.*)\'\s*device\s*=\s*\'(.*)\'\s*class\s*=\s*display",
|
|
pciconf_output,
|
|
re.MULTILINE,
|
|
):
|
|
gpus_list.append(f"{vendor} {device}")
|
|
|
|
return gpus_list
|
|
|
|
@cached_property
|
|
def pretty_value(self) -> [(str, str)]:
|
|
"""Pretty-formats GPUs based on preferences"""
|
|
# No GPU could be detected.
|
|
if not self.value:
|
|
return [(self.name, self._default_strings.get("not_detected"))]
|
|
|
|
# Join the results only if `one_line` option is enabled.
|
|
if self.options.get("one_line"):
|
|
return [(self.name, ", ".join(self.value))]
|
|
else:
|
|
return map(lambda gpu_device: (self.name, gpu_device), self.value)
|