116
116
import os
117
117
import re
118
118
import sys
119
+ import subprocess
120
+ import functools
121
+ import itertools
119
122
120
123
### Globals & Constants
121
124
@@ -600,22 +603,6 @@ def _follow_symlinks(filepath):
600
603
os .path .join (os .path .dirname (filepath ), os .readlink (filepath )))
601
604
return filepath
602
605
603
- def _syscmd_uname (option , default = '' ):
604
-
605
- """ Interface to the system's uname command.
606
- """
607
- if sys .platform in ('dos' , 'win32' , 'win16' ):
608
- # XXX Others too ?
609
- return default
610
-
611
- import subprocess
612
- try :
613
- output = subprocess .check_output (('uname' , option ),
614
- stderr = subprocess .DEVNULL ,
615
- text = True )
616
- except (OSError , subprocess .CalledProcessError ):
617
- return default
618
- return (output .strip () or default )
619
606
620
607
def _syscmd_file (target , default = '' ):
621
608
@@ -736,13 +723,89 @@ def architecture(executable=sys.executable, bits='', linkage=''):
736
723
737
724
return bits , linkage
738
725
726
+
727
+ def _get_machine_win32 ():
728
+ # Try to use the PROCESSOR_* environment variables
729
+ # available on Win XP and later; see
730
+ # http://support.microsoft.com/kb/888731 and
731
+ # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
732
+
733
+ # WOW64 processes mask the native architecture
734
+ return (
735
+ os .environ .get ('PROCESSOR_ARCHITEW6432' , '' ) or
736
+ os .environ .get ('PROCESSOR_ARCHITECTURE' , '' )
737
+ )
738
+
739
+
740
+ class _Processor :
741
+ @classmethod
742
+ def get (cls ):
743
+ func = getattr (cls , f'get_{ sys .platform } ' , cls .from_subprocess )
744
+ return func () or ''
745
+
746
+ def get_win32 ():
747
+ return os .environ .get ('PROCESSOR_IDENTIFIER' , _get_machine_win32 ())
748
+
749
+ def get_OpenVMS ():
750
+ try :
751
+ import vms_lib
752
+ except ImportError :
753
+ pass
754
+ else :
755
+ csid , cpu_number = vms_lib .getsyi ('SYI$_CPU' , 0 )
756
+ return 'Alpha' if cpu_number >= 128 else 'VAX'
757
+
758
+ def from_subprocess ():
759
+ """
760
+ Fall back to `uname -p`
761
+ """
762
+ try :
763
+ return subprocess .check_output (
764
+ ['uname' , '-p' ],
765
+ stderr = subprocess .DEVNULL ,
766
+ text = True ,
767
+ ).strip ()
768
+ except (OSError , subprocess .CalledProcessError ):
769
+ pass
770
+
771
+
772
+ def _unknown_as_blank (val ):
773
+ return '' if val == 'unknown' else val
774
+
775
+
739
776
### Portable uname() interface
740
777
741
- uname_result = collections .namedtuple ("uname_result" ,
742
- "system node release version machine processor" )
778
+ class uname_result (
779
+ collections .namedtuple (
780
+ "uname_result_base" ,
781
+ "system node release version machine" )
782
+ ):
783
+ """
784
+ A uname_result that's largely compatible with a
785
+ simple namedtuple except that 'platform' is
786
+ resolved late and cached to avoid calling "uname"
787
+ except when needed.
788
+ """
789
+
790
+ @functools .cached_property
791
+ def processor (self ):
792
+ return _unknown_as_blank (_Processor .get ())
793
+
794
+ def __iter__ (self ):
795
+ return itertools .chain (
796
+ super ().__iter__ (),
797
+ (self .processor ,)
798
+ )
799
+
800
+ def __getitem__ (self , key ):
801
+ if key == 5 :
802
+ return self .processor
803
+ return super ().__getitem__ (key )
804
+
743
805
744
806
_uname_cache = None
745
807
808
+
746
809
def uname ():
747
810
748
811
""" Fairly portable uname interface. Returns a tuple
@@ -756,52 +819,30 @@ def uname():
756
819
757
820
"""
758
821
global _uname_cache
759
- no_os_uname = 0
760
822
761
823
if _uname_cache is not None :
762
824
return _uname_cache
763
825
764
- processor = ''
765
-
766
826
# Get some infos from the builtin os.uname API...
767
827
try :
768
- system , node , release , version , machine = os .uname ()
828
+ system , node , release , version , machine = infos = os .uname ()
769
829
except AttributeError :
770
- no_os_uname = 1
771
-
772
- if no_os_uname or not list (filter (None , (system , node , release , version , machine ))):
773
- # Hmm, no there is either no uname or uname has returned
774
- #'unknowns'... we'll have to poke around the system then.
775
- if no_os_uname :
776
- system = sys .platform
777
- release = ''
778
- version = ''
779
- node = _node ()
780
- machine = ''
830
+ system = sys .platform
831
+ node = _node ()
832
+ release = version = machine = ''
833
+ infos = ()
781
834
782
- use_syscmd_ver = 1
835
+ if not any (infos ):
836
+ # uname is not available
783
837
784
838
# Try win32_ver() on win32 platforms
785
839
if system == 'win32' :
786
840
release , version , csd , ptype = win32_ver ()
787
- if release and version :
788
- use_syscmd_ver = 0
789
- # Try to use the PROCESSOR_* environment variables
790
- # available on Win XP and later; see
791
- # http://support.microsoft.com/kb/888731 and
792
- # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
793
- if not machine :
794
- # WOW64 processes mask the native architecture
795
- if "PROCESSOR_ARCHITEW6432" in os .environ :
796
- machine = os .environ .get ("PROCESSOR_ARCHITEW6432" , '' )
797
- else :
798
- machine = os .environ .get ('PROCESSOR_ARCHITECTURE' , '' )
799
- if not processor :
800
- processor = os .environ .get ('PROCESSOR_IDENTIFIER' , machine )
841
+ machine = machine or _get_machine_win32 ()
801
842
802
843
# Try the 'ver' system command available on some
803
844
# platforms
804
- if use_syscmd_ver :
845
+ if not ( release and version ) :
805
846
system , release , version = _syscmd_ver (system )
806
847
# Normalize system to what win32_ver() normally returns
807
848
# (_syscmd_ver() tends to return the vendor name as well)
@@ -841,42 +882,15 @@ def uname():
841
882
if not release or release == '0' :
842
883
release = version
843
884
version = ''
844
- # Get processor information
845
- try :
846
- import vms_lib
847
- except ImportError :
848
- pass
849
- else :
850
- csid , cpu_number = vms_lib .getsyi ('SYI$_CPU' , 0 )
851
- if (cpu_number >= 128 ):
852
- processor = 'Alpha'
853
- else :
854
- processor = 'VAX'
855
- if not processor :
856
- # Get processor information from the uname system command
857
- processor = _syscmd_uname ('-p' , '' )
858
-
859
- #If any unknowns still exist, replace them with ''s, which are more portable
860
- if system == 'unknown' :
861
- system = ''
862
- if node == 'unknown' :
863
- node = ''
864
- if release == 'unknown' :
865
- release = ''
866
- if version == 'unknown' :
867
- version = ''
868
- if machine == 'unknown' :
869
- machine = ''
870
- if processor == 'unknown' :
871
- processor = ''
872
885
873
886
# normalize name
874
887
if system == 'Microsoft' and release == 'Windows' :
875
888
system = 'Windows'
876
889
release = 'Vista'
877
890
878
- _uname_cache = uname_result (system , node , release , version ,
879
- machine , processor )
891
+ vals = system , node , release , version , machine
892
+ # Replace 'unknown' values with the more portable ''
893
+ _uname_cache = uname_result (* map (_unknown_as_blank , vals ))
880
894
return _uname_cache
881
895
882
896
### Direct interfaces to some of the uname() return values
0 commit comments