Skip to content

Commit fa02440

Browse files
committed
gh-151929: Get machine ID and uptime on Windows in pythoninfo
* Replace "linux." prefix with "system." in pythoninfo. * Add _winapi.GetTickCount64() function.
1 parent 3db3bba commit fa02440

3 files changed

Lines changed: 109 additions & 27 deletions

File tree

Lib/test/pythoninfo.py

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import warnings
99

1010

11+
MS_WINDOWS = (sys.platform == "win32")
12+
13+
1114
def normalize_text(text):
1215
if text is None:
1316
return None
@@ -906,8 +909,29 @@ def collect_subprocess(info_add):
906909
copy_attributes(info_add, subprocess, 'subprocess.%s', ('_USE_POSIX_SPAWN',))
907910

908911

912+
def winreg_query(path):
913+
try:
914+
import winreg
915+
except ImportError:
916+
return None
917+
918+
key, path = path.split('\\', 1)
919+
sub_key, value = path.rsplit('\\', 1)
920+
if key == "HKEY_LOCAL_MACHINE":
921+
key = winreg.HKEY_LOCAL_MACHINE
922+
else:
923+
raise ValueError(f"unknown key {key!r}")
924+
925+
try:
926+
with winreg.OpenKey(key, sub_key) as key_handle:
927+
result, _ = winreg.QueryValueEx(key_handle, value)
928+
return result
929+
except OSError:
930+
return None
931+
932+
909933
def collect_windows(info_add):
910-
if sys.platform != "win32":
934+
if not MS_WINDOWS:
911935
# Code specific to Windows
912936
return
913937

@@ -999,19 +1023,10 @@ def collect_windows(info_add):
9991023
info_add('windows.ver', line)
10001024

10011025
# windows.developer_mode: get AllowDevelopmentWithoutDevLicense registry
1002-
import winreg
1003-
try:
1004-
key = winreg.OpenKey(
1005-
winreg.HKEY_LOCAL_MACHINE,
1006-
r"SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock")
1007-
subkey = "AllowDevelopmentWithoutDevLicense"
1008-
try:
1009-
value, value_type = winreg.QueryValueEx(key, subkey)
1010-
finally:
1011-
winreg.CloseKey(key)
1012-
except OSError:
1013-
pass
1014-
else:
1026+
value = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows"
1027+
r"\CurrentVersion\AppModelUnlock"
1028+
r"\AllowDevelopmentWithoutDevLicense")
1029+
if value is not None:
10151030
info_add('windows.developer_mode', "enabled" if value else "disabled")
10161031

10171032

@@ -1044,38 +1059,71 @@ def collect_libregrtest_utils(info_add):
10441059
info_add('libregrtests.build_info', ' '.join(utils.get_build_info()))
10451060

10461061

1047-
def linux_get_uptime():
1048-
# Use CLOCK_BOOTTIME if available
1062+
def uptime_boottime():
1063+
# Use CLOCK_BOOTTIME
10491064
import time
10501065
try:
10511066
return time.clock_gettime(time.CLOCK_BOOTTIME)
10521067
except (AttributeError, OSError):
1053-
pass
1068+
return None
1069+
10541070

1055-
# Otherwise, parse the first member of /proc/uptime
1056-
uptime = read_first_line("/proc/uptime")
1057-
if not uptime:
1071+
def uptime_linux():
1072+
# Parse the first member of /proc/uptime
1073+
line = read_first_line("/proc/uptime")
1074+
if not line:
10581075
return
10591076
try:
1060-
parts = uptime.split()
1077+
parts = line.split()
10611078
if not parts:
10621079
return
10631080
return float(parts[0])
10641081
except ValueError:
10651082
return
10661083

10671084

1085+
def uptime_windows():
1086+
try:
1087+
import _winapi
1088+
except ImportError:
1089+
return None
1090+
else:
1091+
return _winapi.GetTickCount64() / 1000.
1092+
1093+
1094+
def get_uptime():
1095+
for func in (uptime_boottime, uptime_linux, uptime_windows):
1096+
uptime = func()
1097+
if uptime is not None:
1098+
return uptime
1099+
return None
1100+
1101+
1102+
def get_machine_id():
1103+
if MS_WINDOWS:
1104+
machine_guid = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft"
1105+
r"\Cryptography\MachineGuid")
1106+
if machine_guid:
1107+
return machine_guid
1108+
1109+
machine_id = read_first_line("/etc/machine-id")
1110+
if machine_id:
1111+
return machine_id
1112+
1113+
return None
1114+
1115+
10681116
def collect_linux(info_add):
10691117
boot_id = read_first_line("/proc/sys/kernel/random/boot_id")
10701118
if boot_id:
1071-
info_add('linux.boot_id', boot_id)
1119+
info_add('system.boot_id', boot_id)
10721120

10731121
# https://www.freedesktop.org/software/systemd/man/latest/machine-id.html
1074-
machine_id = read_first_line("/etc/machine-id")
1122+
machine_id = get_machine_id()
10751123
if machine_id:
1076-
info_add('linux.machine_id', machine_id)
1124+
info_add('system.machine_id', machine_id)
10771125

1078-
uptime = linux_get_uptime()
1126+
uptime = get_uptime()
10791127
if uptime is not None:
10801128
# truncate microseconds
10811129
uptime = int(uptime)
@@ -1084,7 +1132,7 @@ def collect_linux(info_add):
10841132
uptime = str(datetime.timedelta(seconds=uptime))
10851133
except ImportError:
10861134
uptime = f'{uptime} sec'
1087-
info_add('linux.uptime', uptime)
1135+
info_add('system.uptime', uptime)
10881136

10891137

10901138
def collect_info(info):

Modules/_winapi.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3145,6 +3145,21 @@ _winapi_GetProcessMemoryInfo_impl(PyObject *module, HANDLE handle)
31453145
}
31463146

31473147

3148+
/*[clinic input]
3149+
_winapi.GetTickCount64
3150+
3151+
Number of milliseconds that have elapsed since the system was started.
3152+
[clinic start generated code]*/
3153+
3154+
static PyObject *
3155+
_winapi_GetTickCount64_impl(PyObject *module)
3156+
/*[clinic end generated code: output=cb33c0568f0b3ed1 input=77ed6539ac7d6590]*/
3157+
{
3158+
ULONGLONG ticks = GetTickCount64();
3159+
return PyLong_FromUnsignedLongLong(ticks);
3160+
}
3161+
3162+
31483163
static PyMethodDef winapi_functions[] = {
31493164
_WINAPI_CLOSEHANDLE_METHODDEF
31503165
_WINAPI_CONNECTNAMEDPIPE_METHODDEF
@@ -3196,6 +3211,7 @@ static PyMethodDef winapi_functions[] = {
31963211
_WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
31973212
_WINAPI_COPYFILE2_METHODDEF
31983213
_WINAPI_GETPROCESSMEMORYINFO_METHODDEF
3214+
_WINAPI_GETTICKCOUNT64_METHODDEF
31993215
{NULL, NULL}
32003216
};
32013217

Modules/clinic/_winapi.c.h

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)