system-parse-lib 0.0.1__py3-none-any.whl
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.
|
File without changes
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import os, subprocess, getpass, socket
|
|
2
|
+
from dataclasses import dataclass, asdict
|
|
3
|
+
from functools import cache
|
|
4
|
+
|
|
5
|
+
PCI_DEVICES = "/sys/bus/pci/devices"
|
|
6
|
+
PCI_IDS_PATHS = (
|
|
7
|
+
"/usr/share/hwdata/pci.ids",
|
|
8
|
+
"/usr/share/misc/pci.ids",
|
|
9
|
+
"/usr/share/pci.ids",
|
|
10
|
+
)
|
|
11
|
+
VENDORS = {"10de": "NVIDIA", "1002": "AMD", "8086": "Intel"}
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class GPU:
|
|
15
|
+
vendor: str
|
|
16
|
+
model: str
|
|
17
|
+
driver: str | None = None
|
|
18
|
+
|
|
19
|
+
def _read_sysfs(path):
|
|
20
|
+
try:
|
|
21
|
+
with open(path) as f:
|
|
22
|
+
return f.read().strip()
|
|
23
|
+
except OSError:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
@cache
|
|
27
|
+
def _load_pci_ids():
|
|
28
|
+
"""Returns {(vendor_id, device_id): name}"""
|
|
29
|
+
names = {}
|
|
30
|
+
for path in PCI_IDS_PATHS:
|
|
31
|
+
try:
|
|
32
|
+
f = open(path, encoding="utf-8", errors="replace")
|
|
33
|
+
except OSError:
|
|
34
|
+
continue
|
|
35
|
+
with f:
|
|
36
|
+
vendor = None
|
|
37
|
+
for line in f:
|
|
38
|
+
if line.startswith("#") or not line.strip():
|
|
39
|
+
continue
|
|
40
|
+
if line.startswith("C "):
|
|
41
|
+
break
|
|
42
|
+
if line.startswith("\t\t"):
|
|
43
|
+
continue
|
|
44
|
+
if line.startswith("\t"):
|
|
45
|
+
dev_id, _, name = line.strip().partition(" ")
|
|
46
|
+
if vendor:
|
|
47
|
+
names[(vendor, dev_id)] = name
|
|
48
|
+
else:
|
|
49
|
+
vendor = line.split()[0]
|
|
50
|
+
break
|
|
51
|
+
return names
|
|
52
|
+
|
|
53
|
+
class Main():
|
|
54
|
+
def __init__(self):
|
|
55
|
+
def get_distro_info():
|
|
56
|
+
if not os.path.exists('/etc/os-release'):
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
info = {}
|
|
60
|
+
|
|
61
|
+
with open('/etc/os-release') as f:
|
|
62
|
+
for line in f:
|
|
63
|
+
if '=' in line:
|
|
64
|
+
key, value = line.strip().split('=', 1)
|
|
65
|
+
info[key] = value
|
|
66
|
+
return info
|
|
67
|
+
self.distro_info = get_distro_info()
|
|
68
|
+
|
|
69
|
+
def get_distro_id(self):
|
|
70
|
+
if not self.distro_info:
|
|
71
|
+
return None
|
|
72
|
+
return self.distro_info.get('ID', '').strip('"')
|
|
73
|
+
|
|
74
|
+
def get_username(self):
|
|
75
|
+
username = getpass.getuser()
|
|
76
|
+
return username
|
|
77
|
+
|
|
78
|
+
def get_kernel_version(self):
|
|
79
|
+
kernel_version = os.uname().release
|
|
80
|
+
return kernel_version
|
|
81
|
+
|
|
82
|
+
def get_uptime_seconds(self):
|
|
83
|
+
try:
|
|
84
|
+
with open("/proc/uptime") as f:
|
|
85
|
+
return int(float(f.read().split()[0]))
|
|
86
|
+
except (OSError, ValueError, IndexError):
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
def get_pretty_uptime(self):
|
|
90
|
+
seconds = self.get_uptime_seconds()
|
|
91
|
+
if seconds is None:
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
days, rem = divmod(seconds, 86400)
|
|
95
|
+
hours, rem = divmod(rem, 3600)
|
|
96
|
+
minutes = rem // 60
|
|
97
|
+
|
|
98
|
+
parts = []
|
|
99
|
+
if days:
|
|
100
|
+
parts.append(f"{days} day{'s' if days != 1 else ''}")
|
|
101
|
+
if hours:
|
|
102
|
+
parts.append(f"{hours} hour{'s' if hours != 1 else ''}")
|
|
103
|
+
if minutes or not parts:
|
|
104
|
+
parts.append(f"{minutes} minute{'s' if minutes != 1 else ''}")
|
|
105
|
+
return "up " + ", ".join(parts)
|
|
106
|
+
|
|
107
|
+
def get_session_type(self):
|
|
108
|
+
session_type = os.getenv('XDG_SESSION_TYPE')
|
|
109
|
+
if session_type:
|
|
110
|
+
return session_type
|
|
111
|
+
else:
|
|
112
|
+
return "Could not retrieve session type."
|
|
113
|
+
|
|
114
|
+
def get_hostname(self):
|
|
115
|
+
hostname = socket.gethostname()
|
|
116
|
+
return hostname
|
|
117
|
+
|
|
118
|
+
def get_pretty_name(self):
|
|
119
|
+
if not self.distro_info:
|
|
120
|
+
return None
|
|
121
|
+
return self.distro_info.get('PRETTY_NAME', '').strip('"')
|
|
122
|
+
|
|
123
|
+
def get_de(self):
|
|
124
|
+
desktop = os.environ.get("XDG_CURRENT_DESKTOP") or os.environ.get("DESKTOP_SESSION")
|
|
125
|
+
if desktop:
|
|
126
|
+
return desktop
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
def get_cpu(self):
|
|
130
|
+
cpu = ""
|
|
131
|
+
try:
|
|
132
|
+
with open("/proc/cpuinfo", "r", encoding="utf-8") as file:
|
|
133
|
+
for line in file:
|
|
134
|
+
if "model name" in line.lower():
|
|
135
|
+
cpu = line.split(":", 1)[-1].strip()
|
|
136
|
+
break
|
|
137
|
+
except FileNotFoundError:
|
|
138
|
+
return None
|
|
139
|
+
return cpu
|
|
140
|
+
|
|
141
|
+
def get_gpu(self):
|
|
142
|
+
gpus = []
|
|
143
|
+
try:
|
|
144
|
+
devices = sorted(os.listdir(PCI_DEVICES))
|
|
145
|
+
except OSError:
|
|
146
|
+
return gpus
|
|
147
|
+
|
|
148
|
+
ids = _load_pci_ids()
|
|
149
|
+
|
|
150
|
+
for dev in devices:
|
|
151
|
+
base = os.path.join(PCI_DEVICES, dev)
|
|
152
|
+
|
|
153
|
+
pci_class = _read_sysfs(base + "/class")
|
|
154
|
+
if not pci_class or not pci_class.startswith("0x03"):
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
vendor_id = (_read_sysfs(base + "/vendor") or "")[2:]
|
|
158
|
+
device_id = (_read_sysfs(base + "/device") or "")[2:]
|
|
159
|
+
|
|
160
|
+
vendor = VENDORS.get(vendor_id, vendor_id)
|
|
161
|
+
|
|
162
|
+
name = ids.get((vendor_id, device_id), f"Device {device_id}")
|
|
163
|
+
model = name.split('[')[-1].split(']')[0] if '[' in name else name
|
|
164
|
+
|
|
165
|
+
driver = None
|
|
166
|
+
if os.path.exists(base + "/driver"):
|
|
167
|
+
driver = os.path.basename(os.path.realpath(base + "/driver"))
|
|
168
|
+
|
|
169
|
+
gpus.append(GPU(vendor=vendor, model=model, driver=driver))
|
|
170
|
+
|
|
171
|
+
return gpus
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: system-parse-lib
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A for now small python library used for getting information about the system and hardware on linux. Dependency free! (well, not really)
|
|
5
|
+
Project-URL: Homepage, https://github.com/black-mesa-studios/system-parse-lib
|
|
6
|
+
Project-URL: Issues, https://github.com/black-mesa-studios/system-parse-lib/issues/
|
|
7
|
+
Author-email: Artem Ivashyn <artem4ik15082013@gmail.com>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# system-parse-lib
|
|
16
|
+
|
|
17
|
+
A small Python library for reading system information on Linux: OS name, kernel version, uptime, desktop environment, session type, CPU and GPU models and vendors, and basic user details. One module, no third-party dependencies, and no external commands: everything is read from `/etc`, `/proc` and `/sys`.
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+

|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
**Documentation:** https://black-mesa-studios.github.io/system-parse-lib/
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Distro ID and pretty name, read from `/etc/os-release`
|
|
28
|
+
- Current username and hostname
|
|
29
|
+
- Kernel version and uptime (as seconds or readable text)
|
|
30
|
+
- Desktop environment, from `XDG_CURRENT_DESKTOP` or `DESKTOP_SESSION`
|
|
31
|
+
- Session type (Wayland, X11, tty), from `XDG_SESSION_TYPE`
|
|
32
|
+
- CPU model, from `/proc/cpuinfo`
|
|
33
|
+
- GPUs with vendor, model and kernel driver, from `/sys/bus/pci/devices`
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Linux
|
|
38
|
+
- Python 3.10 or newer
|
|
39
|
+
- Optional: a `pci.ids` file (from the `hwdata` or `pciids` package) so `get_gpu()` can show real model names
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
There's no package yet. Clone the repo and copy `systemparselib.py` next to your script:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
git clone https://github.com/black-mesa-studios/system-parse-lib.git
|
|
47
|
+
cp system-parse-lib/systemparselib.py ./
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import systemparselib
|
|
54
|
+
|
|
55
|
+
sysinfo = systemparselib.Main()
|
|
56
|
+
|
|
57
|
+
print(sysinfo.get_pretty_name()) # e.g. Arch Linux
|
|
58
|
+
print(sysinfo.get_de()) # e.g. KDE
|
|
59
|
+
print(sysinfo.get_session_type()) # e.g. wayland
|
|
60
|
+
print(sysinfo.get_kernel_version()) # e.g. 6.11.2-arch1-1
|
|
61
|
+
print(sysinfo.get_pretty_uptime()) # e.g. up 3 hours, 12 minutes
|
|
62
|
+
print(sysinfo.get_cpu()) # e.g. AMD Ryzen 5 5600X 6-Core Processor
|
|
63
|
+
print(sysinfo.get_gpu()) # e.g. [GPU(vendor='AMD', model='...', driver='amdgpu')]
|
|
64
|
+
print(f"{sysinfo.get_username()}@{sysinfo.get_hostname()}")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Functions
|
|
68
|
+
|
|
69
|
+
All functions live on the `Main` class.
|
|
70
|
+
|
|
71
|
+
| Function | Returns | Description |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `get_distro_id()` | `str \| None` | Short distro ID, like `arch` or `ubuntu` |
|
|
74
|
+
| `get_pretty_name()` | `str \| None` | Human-readable OS name |
|
|
75
|
+
| `get_username()` | `str` | Current user's name |
|
|
76
|
+
| `get_hostname()` | `str` | Machine hostname |
|
|
77
|
+
| `get_de()` | `str \| None` | Desktop environment, or `None` if none is set |
|
|
78
|
+
| `get_session_type()` | `str` | Session type from `XDG_SESSION_TYPE`, like `wayland` or `x11` |
|
|
79
|
+
| `get_kernel_version()` | `str` | Kernel release, like `6.11.2-arch1-1` |
|
|
80
|
+
| `get_uptime_seconds()` | `int \| None` | Seconds since boot |
|
|
81
|
+
| `get_pretty_uptime()` | `str \| None` | Readable uptime, like `up 3 hours, 12 minutes` |
|
|
82
|
+
| `get_cpu()` | `str \| None` | CPU model name |
|
|
83
|
+
| `get_gpu()` | `list[GPU]` | One `GPU(vendor, model, driver)` per display device |
|
|
84
|
+
|
|
85
|
+
Full details are in the [documentation](https://black-mesa-studios.github.io/system-parse-lib/).
|
|
86
|
+
|
|
87
|
+
## Testing
|
|
88
|
+
|
|
89
|
+
`test.py` prints the output of every function so you can check it on your machine:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
python3 test.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
Released under the [BSD 3-Clause License](LICENSE). Copyright 2026 Black Mesa Studios.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
system-parse-lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
system-parse-lib/systemparselib.py,sha256=kODuVzQGdlyUtvYuxVlvaFG8mZwaQF3e6_EBt9PD4H8,5033
|
|
3
|
+
system_parse_lib-0.0.1.dist-info/METADATA,sha256=S9IJsE3vmx5g5AjtjN0s6_oCZ8LRMheluheSIkV9j3c,3818
|
|
4
|
+
system_parse_lib-0.0.1.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
5
|
+
system_parse_lib-0.0.1.dist-info/licenses/LICENSE,sha256=OUU7y5SgDmsRqYh0PtRbnl7hdwCO-EHksvXNZiql3uo,1505
|
|
6
|
+
system_parse_lib-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Black Mesa Studios
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|