@@ -309,34 +309,52 @@ def _syscmd_ver(system='', release='', version='',
309
309
version = _norm_version (version )
310
310
return system , release , version
311
311
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
+ ]
340
358
341
359
def win32_is_iot ():
342
360
return win32_edition () in ('IoTUAP' , 'NanoServer' , 'WindowsCoreHeadless' , 'IoTEdgeOS' )
@@ -359,22 +377,40 @@ def win32_edition():
359
377
360
378
return None
361
379
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"
363
401
try :
364
402
from sys import getwindowsversion
365
403
except ImportError :
366
- return release , version , csd , ptype
404
+ return version , csd , ptype , True
367
405
368
406
winver = getwindowsversion ()
407
+ is_client = (getattr (winver , 'product_type' , 1 ) == 1 )
369
408
try :
370
- major , minor , build = map (int , _syscmd_ver ()[2 ].split ('.' ))
409
+ version = _syscmd_ver ()[2 ]
410
+ major , minor , build = map (int , version .split ('.' ))
371
411
except ValueError :
372
412
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 )
378
414
379
415
# getwindowsversion() reflect the compatibility mode Python is
380
416
# running under, and so the service pack value is only going to be
@@ -386,12 +422,6 @@ def win32_ver(release='', version='', csd='', ptype=''):
386
422
if csd [:13 ] == 'Service Pack ' :
387
423
csd = 'SP' + csd [13 :]
388
424
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
-
395
425
try :
396
426
try :
397
427
import winreg
@@ -407,6 +437,18 @@ def win32_ver(release='', version='', csd='', ptype=''):
407
437
except OSError :
408
438
pass
409
439
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
+
410
452
return release , version , csd , ptype
411
453
412
454
@@ -725,6 +767,21 @@ def _get_machine_win32():
725
767
# http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
726
768
727
769
# 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
728
785
return (
729
786
os .environ .get ('PROCESSOR_ARCHITEW6432' , '' ) or
730
787
os .environ .get ('PROCESSOR_ARCHITECTURE' , '' )
@@ -738,7 +795,12 @@ def get(cls):
738
795
return func () or ''
739
796
740
797
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 } '
742
804
743
805
def get_OpenVMS ():
744
806
try :
0 commit comments