[3.14] gh-151929: Get machine ID and uptime on Windows in pythoninfo (#152146) (#152187) (#152193)

[3.15] gh-151929: Get machine ID and uptime on Windows in pythoninfo (#152146) (#152187)

gh-151929: Get machine ID and uptime on Windows in pythoninfo (#152146)

* Replace "linux." prefix with "system." in pythoninfo.
* Add _winapi.GetTickCount64() function.

(cherry picked from commit f9910519af)
(cherry picked from commit ae4c2c126b)
This commit is contained in:
Victor Stinner 2026-06-25 15:08:35 +02:00 committed by GitHub
parent 7e30c9ebb9
commit be65a38eb7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 110 additions and 27 deletions

View file

@ -8,6 +8,9 @@
import warnings
MS_WINDOWS = (sys.platform == "win32")
def normalize_text(text):
if text is None:
return None
@ -894,8 +897,30 @@ def collect_subprocess(info_add):
copy_attributes(info_add, subprocess, 'subprocess.%s', ('_USE_POSIX_SPAWN',))
def winreg_query(path):
try:
import winreg
except ImportError:
return None
key, path = path.split('\\', 1)
sub_key, value = path.rsplit('\\', 1)
if key == "HKEY_LOCAL_MACHINE":
key = winreg.HKEY_LOCAL_MACHINE
else:
raise ValueError(f"unknown key {key!r}")
try:
access = winreg.KEY_READ | winreg.KEY_WOW64_64KEY
with winreg.OpenKey(key, sub_key, access=access) as key_handle:
result, _ = winreg.QueryValueEx(key_handle, value)
return result
except OSError:
return None
def collect_windows(info_add):
if sys.platform != "win32":
if not MS_WINDOWS:
# Code specific to Windows
return
@ -980,19 +1005,10 @@ def collect_windows(info_add):
info_add('windows.ver', line)
# windows.developer_mode: get AllowDevelopmentWithoutDevLicense registry
import winreg
try:
key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
r"SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock")
subkey = "AllowDevelopmentWithoutDevLicense"
try:
value, value_type = winreg.QueryValueEx(key, subkey)
finally:
winreg.CloseKey(key)
except OSError:
pass
else:
value = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows"
r"\CurrentVersion\AppModelUnlock"
r"\AllowDevelopmentWithoutDevLicense")
if value is not None:
info_add('windows.developer_mode', "enabled" if value else "disabled")
@ -1025,20 +1041,22 @@ def collect_libregrtest_utils(info_add):
info_add('libregrtests.build_info', ' '.join(utils.get_build_info()))
def linux_get_uptime():
# Use CLOCK_BOOTTIME if available
def uptime_boottime():
# Use CLOCK_BOOTTIME
import time
try:
return time.clock_gettime(time.CLOCK_BOOTTIME)
except (AttributeError, OSError):
pass
return None
# Otherwise, parse the first member of /proc/uptime
uptime = read_first_line("/proc/uptime")
if not uptime:
def uptime_linux():
# Parse the first member of /proc/uptime
line = read_first_line("/proc/uptime")
if not line:
return
try:
parts = uptime.split()
parts = line.split()
if not parts:
return
return float(parts[0])
@ -1046,17 +1064,48 @@ def linux_get_uptime():
return
def uptime_windows():
try:
import _winapi
except ImportError:
return None
else:
return _winapi.GetTickCount64() / 1000.
def get_uptime():
for func in (uptime_boottime, uptime_linux, uptime_windows):
uptime = func()
if uptime is not None:
return uptime
return None
def get_machine_id():
if MS_WINDOWS:
machine_guid = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft"
r"\Cryptography\MachineGuid")
if machine_guid:
return machine_guid
machine_id = read_first_line("/etc/machine-id")
if machine_id:
return machine_id
return None
def collect_linux(info_add):
boot_id = read_first_line("/proc/sys/kernel/random/boot_id")
if boot_id:
info_add('linux.boot_id', boot_id)
info_add('system.boot_id', boot_id)
# https://www.freedesktop.org/software/systemd/man/latest/machine-id.html
machine_id = read_first_line("/etc/machine-id")
machine_id = get_machine_id()
if machine_id:
info_add('linux.machine_id', machine_id)
info_add('system.machine_id', machine_id)
uptime = linux_get_uptime()
uptime = get_uptime()
if uptime is not None:
# truncate microseconds
uptime = int(uptime)
@ -1065,7 +1114,7 @@ def collect_linux(info_add):
uptime = str(datetime.timedelta(seconds=uptime))
except ImportError:
uptime = f'{uptime} sec'
info_add('linux.uptime', uptime)
info_add('system.uptime', uptime)
def collect_info(info):

View file

@ -2960,6 +2960,21 @@ _winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name,
}
/*[clinic input]
_winapi.GetTickCount64
Number of milliseconds that have elapsed since the system was started.
[clinic start generated code]*/
static PyObject *
_winapi_GetTickCount64_impl(PyObject *module)
/*[clinic end generated code: output=cb33c0568f0b3ed1 input=77ed6539ac7d6590]*/
{
ULONGLONG ticks = GetTickCount64();
return PyLong_FromUnsignedLongLong(ticks);
}
static PyMethodDef winapi_functions[] = {
_WINAPI_CLOSEHANDLE_METHODDEF
_WINAPI_CONNECTNAMEDPIPE_METHODDEF
@ -3006,6 +3021,7 @@ static PyMethodDef winapi_functions[] = {
_WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
_WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
_WINAPI_COPYFILE2_METHODDEF
_WINAPI_GETTICKCOUNT64_METHODDEF
{NULL, NULL}
};

View file

@ -2161,4 +2161,22 @@ exit:
return return_value;
}
/*[clinic end generated code: output=6cd07628af447d0a input=a9049054013a1b77]*/
PyDoc_STRVAR(_winapi_GetTickCount64__doc__,
"GetTickCount64($module, /)\n"
"--\n"
"\n"
"Number of milliseconds that have elapsed since the system was started.");
#define _WINAPI_GETTICKCOUNT64_METHODDEF \
{"GetTickCount64", (PyCFunction)_winapi_GetTickCount64, METH_NOARGS, _winapi_GetTickCount64__doc__},
static PyObject *
_winapi_GetTickCount64_impl(PyObject *module);
static PyObject *
_winapi_GetTickCount64(PyObject *module, PyObject *Py_UNUSED(ignored))
{
return _winapi_GetTickCount64_impl(module);
}
/*[clinic end generated code: output=4a408e816118d0a6 input=a9049054013a1b77]*/