@@ -309,34 +309,52 @@ def _syscmd_ver(system='', release='', version='',
309309 version = _norm_version (version )
310310 return system , release , version
311311
312- _WIN32_CLIENT_RELEASES = {
313- (5 , 0 ): "2000" ,
314- (5 , 1 ): "XP" ,
315- # Strictly, 5.2 client is XP 64-bit, but platform.py historically
316- # has always called it 2003 Server
317- (5 , 2 ): "2003Server" ,
318- (5 , None ): "post2003" ,
319-
320- (6 , 0 ): "Vista" ,
321- (6 , 1 ): "7" ,
322- (6 , 2 ): "8" ,
323- (6 , 3 ): "8.1" ,
324- (6 , None ): "post8.1" ,
325-
326- (10 , 0 ): "10" ,
327- (10 , None ): "post10" ,
328- }
329-
330- # Server release name lookup will default to client names if necessary
331- _WIN32_SERVER_RELEASES = {
332- (5 , 2 ): "2003Server" ,
333-
334- (6 , 0 ): "2008Server" ,
335- (6 , 1 ): "2008ServerR2" ,
336- (6 , 2 ): "2012Server" ,
337- (6 , 3 ): "2012ServerR2" ,
338- (6 , None ): "post2012ServerR2" ,
339- }
312+ try :
313+ import _wmi
314+ except ImportError :
315+ def _wmi_query (* keys ):
316+ raise OSError ("not supported" )
317+ else :
318+ def _wmi_query (table , * keys ):
319+ table = {
320+ "OS" : "Win32_OperatingSystem" ,
321+ "CPU" : "Win32_Processor" ,
322+ }[table ]
323+ data = _wmi .exec_query ("SELECT {} FROM {}" .format (
324+ "," .join (keys ),
325+ table ,
326+ )).split ("\0 " )
327+ split_data = (i .partition ("=" ) for i in data )
328+ dict_data = {i [0 ]: i [2 ] for i in split_data }
329+ return (dict_data [k ] for k in keys )
330+
331+
332+ _WIN32_CLIENT_RELEASES = [
333+ ((10 , 1 , 0 ), "post11" ),
334+ ((10 , 0 , 22000 ), "11" ),
335+ ((6 , 4 , 0 ), "10" ),
336+ ((6 , 3 , 0 ), "8.1" ),
337+ ((6 , 2 , 0 ), "8" ),
338+ ((6 , 1 , 0 ), "7" ),
339+ ((6 , 0 , 0 ), "Vista" ),
340+ ((5 , 2 , 3790 ), "XP64" ),
341+ ((5 , 2 , 0 ), "XPMedia" ),
342+ ((5 , 1 , 0 ), "XP" ),
343+ ((5 , 0 , 0 ), "2000" ),
344+ ]
345+
346+ _WIN32_SERVER_RELEASES = [
347+ ((10 , 1 , 0 ), "post2022Server" ),
348+ ((10 , 0 , 20348 ), "2022Server" ),
349+ ((10 , 0 , 17763 ), "2019Server" ),
350+ ((6 , 4 , 0 ), "2016Server" ),
351+ ((6 , 3 , 0 ), "2012ServerR2" ),
352+ ((6 , 2 , 0 ), "2012Server" ),
353+ ((6 , 1 , 0 ), "2008ServerR2" ),
354+ ((6 , 0 , 0 ), "2008Server" ),
355+ ((5 , 2 , 0 ), "2003Server" ),
356+ ((5 , 0 , 0 ), "2000Server" ),
357+ ]
340358
341359def win32_is_iot ():
342360 return win32_edition () in ('IoTUAP' , 'NanoServer' , 'WindowsCoreHeadless' , 'IoTEdgeOS' )
@@ -359,22 +377,40 @@ def win32_edition():
359377
360378 return None
361379
362- def win32_ver (release = '' , version = '' , csd = '' , ptype = '' ):
380+ def _win32_ver (version , csd , ptype ):
381+ # Try using WMI first, as this is the canonical source of data
382+ try :
383+ (version , product_type , ptype , spmajor , spminor ) = _wmi_query (
384+ 'OS' ,
385+ 'Version' ,
386+ 'ProductType' ,
387+ 'BuildType' ,
388+ 'ServicePackMajorVersion' ,
389+ 'ServicePackMinorVersion' ,
390+ )
391+ is_client = (int (product_type ) == 1 )
392+ if spminor and spminor != '0' :
393+ csd = f'SP{ spmajor } .{ spminor } '
394+ else :
395+ csd = f'SP{ spmajor } '
396+ return version , csd , ptype , is_client
397+ except OSError :
398+ pass
399+
400+ # Fall back to a combination of sys.getwindowsversion and "ver"
363401 try :
364402 from sys import getwindowsversion
365403 except ImportError :
366- return release , version , csd , ptype
404+ return version , csd , ptype , True
367405
368406 winver = getwindowsversion ()
407+ is_client = (getattr (winver , 'product_type' , 1 ) == 1 )
369408 try :
370- major , minor , build = map (int , _syscmd_ver ()[2 ].split ('.' ))
409+ version = _syscmd_ver ()[2 ]
410+ major , minor , build = map (int , version .split ('.' ))
371411 except ValueError :
372412 major , minor , build = winver .platform_version or winver [:3 ]
373- version = '{0}.{1}.{2}' .format (major , minor , build )
374-
375- release = (_WIN32_CLIENT_RELEASES .get ((major , minor )) or
376- _WIN32_CLIENT_RELEASES .get ((major , None )) or
377- release )
413+ version = '{0}.{1}.{2}' .format (major , minor , build )
378414
379415 # getwindowsversion() reflect the compatibility mode Python is
380416 # running under, and so the service pack value is only going to be
@@ -386,12 +422,6 @@ def win32_ver(release='', version='', csd='', ptype=''):
386422 if csd [:13 ] == 'Service Pack ' :
387423 csd = 'SP' + csd [13 :]
388424
389- # VER_NT_SERVER = 3
390- if getattr (winver , 'product_type' , None ) == 3 :
391- release = (_WIN32_SERVER_RELEASES .get ((major , minor )) or
392- _WIN32_SERVER_RELEASES .get ((major , None )) or
393- release )
394-
395425 try :
396426 try :
397427 import winreg
@@ -407,6 +437,18 @@ def win32_ver(release='', version='', csd='', ptype=''):
407437 except OSError :
408438 pass
409439
440+ return version , csd , ptype , is_client
441+
442+ def win32_ver (release = '' , version = '' , csd = '' , ptype = '' ):
443+ is_client = False
444+
445+ version , csd , ptype , is_client = _win32_ver (version , csd , ptype )
446+
447+ if version :
448+ intversion = tuple (map (int , version .split ('.' )))
449+ releases = _WIN32_CLIENT_RELEASES if is_client else _WIN32_SERVER_RELEASES
450+ release = next ((r for v , r in releases if v <= intversion ), release )
451+
410452 return release , version , csd , ptype
411453
412454
@@ -725,6 +767,21 @@ def _get_machine_win32():
725767 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
726768
727769 # WOW64 processes mask the native architecture
770+ try :
771+ [arch , * _ ] = _wmi_query ('CPU' , 'Architecture' )
772+ except OSError :
773+ pass
774+ else :
775+ try :
776+ arch = ['x86' , 'MIPS' , 'Alpha' , 'PowerPC' , None ,
777+ 'ARM' , 'ia64' , None , None ,
778+ 'AMD64' , None , None , 'ARM64' ,
779+ ][int (arch )]
780+ except (ValueError , IndexError ):
781+ pass
782+ else :
783+ if arch :
784+ return arch
728785 return (
729786 os .environ .get ('PROCESSOR_ARCHITEW6432' , '' ) or
730787 os .environ .get ('PROCESSOR_ARCHITECTURE' , '' )
@@ -738,7 +795,12 @@ def get(cls):
738795 return func () or ''
739796
740797 def get_win32 ():
741- return os .environ .get ('PROCESSOR_IDENTIFIER' , _get_machine_win32 ())
798+ try :
799+ manufacturer , caption = _wmi_query ('CPU' , 'Manufacturer' , 'Caption' )
800+ except OSError :
801+ return os .environ .get ('PROCESSOR_IDENTIFIER' , _get_machine_win32 ())
802+ else :
803+ return f'{ caption } , { manufacturer } '
742804
743805 def get_OpenVMS ():
744806 try :
0 commit comments