https://github.com/python/cpython/commit/7d5e2dd398eff5ac3aa60133a09c313f6b7b6d64
commit: 7d5e2dd398eff5ac3aa60133a09c313f6b7b6d64
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: vstinner <[email protected]>
date: 2026-06-25T00:00:32Z
summary:

[3.15] gh-151929: Get boot ID, machine ID and uptime in test.pythoninfo 
(GH-152127) (#152134)

gh-151929: Get boot ID, machine ID and uptime in test.pythoninfo (GH-152127)
(cherry picked from commit 3db3bba4d1feb3a9fbfcd368d470db17b5336dc4)


GHA: Run test.pythoninfo on the "Cross build Linux" job.

Co-authored-by: Victor Stinner <[email protected]>

files:
M .github/workflows/build.yml
M Lib/test/pythoninfo.py

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e08891ea88b5408..89be2d9c8ed84de 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -648,6 +648,9 @@ jobs:
         run: ./configure --prefix="$BUILD_DIR/cross-python" 
--with-build-python="$BUILD_DIR/host-python/bin/python3"
       - name: Install cross Python
         run: make -j8 install
+      - name: Display build info
+        run: |
+          "$BUILD_DIR/cross-python/bin/python3" -m test.pythoninfo
       - name: Run test subset with host build
         run: |
           "$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig 
test_site test_embed
diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index 7f735d75b318e7f..067e218f797364c 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -16,6 +16,15 @@ def normalize_text(text):
     return text.strip()
 
 
+def read_first_line(filename):
+    # Get the first line of a text file and strip trailing spaces
+    try:
+        with open(filename, encoding="utf-8") as fp:
+            return fp.readline().rstrip()
+    except OSError:
+        return ''
+
+
 class PythonInfo:
     def __init__(self):
         self.info = {}
@@ -1015,14 +1024,9 @@ def collect_fips(info_add):
     if _hashlib is not None:
         call_func(info_add, 'fips.openssl_fips_mode', _hashlib, 
'get_fips_mode')
 
-    try:
-        with open("/proc/sys/crypto/fips_enabled", encoding="utf-8") as fp:
-            line = fp.readline().rstrip()
-
-        if line:
-            info_add('fips.linux_crypto_fips_enabled', line)
-    except OSError:
-        pass
+    fips_enabled = read_first_line("/proc/sys/crypto/fips_enabled")
+    if fips_enabled:
+        info_add('fips.linux_crypto_fips_enabled', fips_enabled)
 
 
 def collect_tempfile(info_add):
@@ -1040,6 +1044,49 @@ 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
+    import time
+    try:
+        return time.clock_gettime(time.CLOCK_BOOTTIME)
+    except (AttributeError, OSError):
+        pass
+
+    # Otherwise, parse the first member of /proc/uptime
+    uptime = read_first_line("/proc/uptime")
+    if not uptime:
+        return
+    try:
+        parts = uptime.split()
+        if not parts:
+            return
+        return float(parts[0])
+    except ValueError:
+        return
+
+
+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)
+
+    # https://www.freedesktop.org/software/systemd/man/latest/machine-id.html
+    machine_id = read_first_line("/etc/machine-id")
+    if machine_id:
+        info_add('linux.machine_id', machine_id)
+
+    uptime = linux_get_uptime()
+    if uptime is not None:
+        # truncate microseconds
+        uptime = int(uptime)
+        try:
+            import datetime
+            uptime = str(datetime.timedelta(seconds=uptime))
+        except ImportError:
+            uptime = f'{uptime} sec'
+        info_add('linux.uptime', uptime)
+
+
 def collect_info(info):
     error = False
     info_add = info.add
@@ -1081,6 +1128,7 @@ def collect_info(info):
         collect_zlib,
         collect_zstd,
         collect_libregrtest_utils,
+        collect_linux,
 
         # Collecting from tests should be last as they have side effects.
         collect_test_socket,

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to