https://github.com/python/cpython/commit/0d3a87f231540af0a97cae8469010ca08b0456eb
commit: 0d3a87f231540af0a97cae8469010ca08b0456eb
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: vstinner <[email protected]>
date: 2026-07-02T13:24:52Z
summary:

[3.13] gh-152680: Detect virtualization on Windows in pythoninfo (GH-152824) 
(#152888)

gh-152680: Detect virtualization on Windows in pythoninfo (GH-152824)

Use WMI to detect virtualization on Windows.

Replace wmic command with _wmi module to get the operating system caption and
version.

The wmic tool is deprecated since January 2024:
https://techcommunity.microsoft.com/blog/windows-itpro-blog/wmi-command-line-wmic-utility-deprecation-next-steps/4039242

For example, it's no longer installed in Windows images on GitHub
Action.

Fix also run_command(): no longer try to spawn a subprocess if the
platform doesn't support subprocess. It avoids logging run_command()
errors.
(cherry picked from commit 4e4869b62fa91e26117b1d9136f60b58c9f505a5)

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

files:
M Lib/test/pythoninfo.py

diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index f1dd3629ca2c83..a434ccbb7ed5d4 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -450,6 +450,12 @@ def format_attr(attr, value):
 
 def run_command(cmd, check=True, **kwargs):
     import subprocess
+    from test.support import has_subprocess_support
+
+    if not has_subprocess_support:
+        # subprocess is not supported by the current platform
+        return ''
+
     timeout = COMMAND_TIMEOUT
 
     cmd_str = ' '.join(cmd)
@@ -949,6 +955,24 @@ def winreg_query(path):
         return None
 
 
+def wmi_query(query):
+    try:
+        import _wmi
+    except ImportError:
+        return {}
+
+    try:
+        data = _wmi.exec_query(query)
+    except OSError:
+        return {}
+
+    dict_data = {}
+    for item in data.split("\0"):
+        key, _, value = item.partition("=")
+        dict_data[key] = value
+    return dict_data
+
+
 def collect_windows(info_add):
     if not MS_WINDOWS:
         # Code specific to Windows
@@ -988,22 +1012,14 @@ def collect_windows(info_add):
     except (ImportError, AttributeError):
         pass
 
-    # windows.version_caption: "wmic os get Caption,Version /value" command
-    output = run_command(["wmic", "os", "get", "Caption,Version", "/value"],
-                         # When wmic.exe output is redirected to a pipe,
-                         # it uses the OEM code page
-                         encoding="oem")
-    if output:
-        for line in output.splitlines():
-            line = line.strip()
-            if line.startswith('Caption='):
-                line = line.removeprefix('Caption=').strip()
-                if line:
-                    info_add('windows.version_caption', line)
-            elif line.startswith('Version='):
-                line = line.removeprefix('Version=').strip()
-                if line:
-                    info_add('windows.version', line)
+    # Get operating system caption and version using WMI
+    data = wmi_query("SELECT Caption, Version FROM Win32_OperatingSystem")
+    caption = data.get('Caption', '')
+    if caption:
+        info_add('windows.version_caption', caption)
+    version = data.get('Version', '')
+    if version:
+        info_add('windows.version', version)
 
     # windows.ver: "ver" command
     output = run_command(["ver"], shell=True)
@@ -1121,7 +1137,97 @@ def get_machine_id():
     return None
 
 
-def detect_virt():
+def detect_virt_windows(info_add):
+    # On Windows, use WMI to detect the virtualization.
+    #
+    # Microsoft Hyper-V:
+    # - Win32_Bios.Version = 'VRTUAL - 12001807'
+    # - Win32_Bios.Manufacturer = 'American Megatrends Inc.'
+    # - Win32_ComputerSystem.Model = 'Virtual Machine'
+    # - Win32_ComputerSystem.Manufacturer = 'Microsoft Corporation'
+    #
+    # VMware:
+    # - Win32_ComputerSystem.Model = 'VMware'
+    # - Win32_ComputerSystem.Manufacturer = 'VMWare' (uppercase W in Ware)
+    # - Win32_Bios.SerialNumber starts with 'VMware-'
+    #
+    # QEMU:
+    # - Win32_ComputerSystem.Manufacturer = 'QEMU'
+    # - Win32_ComputerSystem.Model = 'Standard PC (Q35 + ICH9, 2009)'
+    # - Win32_Bios.Version = 'BOCHS  - 1'
+    # - Win32_Bios.Manufacturer = 'EDK II'
+    #
+    # Parallels:
+    # - Win32_Bios.Version = 'PARALLELS'
+    #
+    # VirtualBox:
+    # - Win32_Bios.Version = 'VBOX'
+    # - Win32_ComputerSystem.Model = 'VirtualBox'
+    # - Win32_ComputerSystem.Manufacturer = 'innotek GmbH'
+    #
+    # Amazon EC2:
+    # - Win32_Bios.Version = 'AMAZON - 1'
+    # - Win32_Bios.Manufacturer = 'Amazon EC2'
+    # - Win32_ComputerSystem.Model = 'm7i.4xlarge'
+    # - Win32_ComputerSystem.Manufacturer = 'Amazon EC2'
+
+    KNOWN_VIRT = (
+        'Amazon EC2',
+        'QEMU',
+        'VMware',
+        'VirtualBox',
+        'Xen',
+        'oVirt',
+    )
+    KNOWN_BIOS_VERSIONS = {
+        'PARALLELS': 'Parallels',
+        'VBOX': 'VirtualBox',
+    }
+
+    computer = wmi_query('SELECT Model, Manufacturer FROM 
Win32_ComputerSystem')
+    computer_model = computer.get('Model', '')
+    computer_manufacturer = computer.get('Manufacturer', '')
+    if computer_manufacturer == 'Amazon EC2':
+        # Log the VM model (ex: 'm7i.4xlarge')
+        info_add('system.computer.model', computer_model)
+        return computer_manufacturer
+    if computer_model in KNOWN_VIRT:
+        return computer_model
+    if computer_manufacturer in KNOWN_VIRT:
+        return computer_manufacturer
+
+    bios = wmi_query('SELECT Version, Manufacturer FROM Win32_Bios')
+
+    bios_version = bios.get('Version', '')
+    if bios_version in KNOWN_VIRT:
+        return bios_version
+    if (bios_version.startswith('VRTUAL - ')
+        and computer_manufacturer == 'Microsoft Corporation'):
+        return 'Microsoft Hyper-V'
+    try:
+        return KNOWN_BIOS_VERSIONS[bios_version]
+    except KeyError:
+        pass
+
+    bios_manufacturer = bios.get('Manufacturer', '')
+    if bios_manufacturer in KNOWN_VIRT:
+        return bios_manufacturer
+
+    # Log the values to update the code if a new VM is discovered
+    if computer_model:
+        info_add('system.computer.model', computer_model)
+    if computer_manufacturer:
+        info_add('system.computer.manufacturer', computer_manufacturer)
+    if bios_version:
+        info_add('system.bios.version', bios_version)
+    if bios_manufacturer:
+        info_add('system.bios.manufacturer', bios_manufacturer)
+
+
+def detect_virt(info_add):
+    if MS_WINDOWS:
+        return detect_virt_windows(info_add)
+
     # Run systemd-detect-virt command
     virt = run_command(["systemd-detect-virt"], check=False)
     if virt and virt != "none":
@@ -1179,7 +1285,7 @@ def collect_system(info_add):
             uptime = f'{uptime} sec'
         info_add('system.uptime', uptime)
 
-    virt = detect_virt()
+    virt = detect_virt(info_add)
     if virt:
         info_add('system.virt', virt)
 

_______________________________________________
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