mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	bpo-35346, platform: replace os.popen() with subprocess (GH-10786)
Replace os.popen() with subprocess.check_output() in the platform module: * platform.uname() (its _syscmd_ver() helper function) now redirects stderr to DEVNULL. * Remove platform.DEV_NULL. * _syscmd_uname() and _syscmd_file() no longer catch AttributeError. The "except AttributeError:" was only needed in Python 2, when os.popen() was not always available. In Python 3, subprocess.check_output() is always available.
This commit is contained in:
		
							parent
							
								
									9ebe8794f0
								
							
						
					
					
						commit
						3a521f0b61
					
				
					 3 changed files with 30 additions and 48 deletions
				
			
		|  | @ -119,19 +119,6 @@ | ||||||
| 
 | 
 | ||||||
| ### Globals & Constants | ### Globals & Constants | ||||||
| 
 | 
 | ||||||
| # Determine the platform's /dev/null device |  | ||||||
| try: |  | ||||||
|     DEV_NULL = os.devnull |  | ||||||
| except AttributeError: |  | ||||||
|     # os.devnull was added in Python 2.4, so emulate it for earlier |  | ||||||
|     # Python versions |  | ||||||
|     if sys.platform in ('dos', 'win32', 'win16'): |  | ||||||
|         # Use the old CP/M NUL as device name |  | ||||||
|         DEV_NULL = 'NUL' |  | ||||||
|     else: |  | ||||||
|         # Standard Unix uses /dev/null |  | ||||||
|         DEV_NULL = '/dev/null' |  | ||||||
| 
 |  | ||||||
| # Helper for comparing two version number strings. | # Helper for comparing two version number strings. | ||||||
| # Based on the description of the PHP's version_compare(): | # Based on the description of the PHP's version_compare(): | ||||||
| # http://php.net/manual/en/function.version-compare.php | # http://php.net/manual/en/function.version-compare.php | ||||||
|  | @ -288,16 +275,15 @@ def _syscmd_ver(system='', release='', version='', | ||||||
|         return system, release, version |         return system, release, version | ||||||
| 
 | 
 | ||||||
|     # Try some common cmd strings |     # Try some common cmd strings | ||||||
|  |     import subprocess | ||||||
|     for cmd in ('ver', 'command /c ver', 'cmd /c ver'): |     for cmd in ('ver', 'command /c ver', 'cmd /c ver'): | ||||||
|         try: |         try: | ||||||
|             pipe = os.popen(cmd) |             info = subprocess.check_output(cmd, | ||||||
|             info = pipe.read() |                                            stderr=subprocess.DEVNULL, | ||||||
|             if pipe.close(): |                                            text=True, | ||||||
|                 raise OSError('command failed') |                                            shell=True) | ||||||
|             # XXX How can I suppress shell errors from being written |         except (OSError, subprocess.CalledProcessError) as why: | ||||||
|             #     to stderr ? |             #print('Command %s failed: %s' % (cmd, why)) | ||||||
|         except OSError as why: |  | ||||||
|             #print 'Command %s failed: %s' % (cmd, why) |  | ||||||
|             continue |             continue | ||||||
|         else: |         else: | ||||||
|             break |             break | ||||||
|  | @ -602,16 +588,15 @@ def _syscmd_uname(option, default=''): | ||||||
|     if sys.platform in ('dos', 'win32', 'win16'): |     if sys.platform in ('dos', 'win32', 'win16'): | ||||||
|         # XXX Others too ? |         # XXX Others too ? | ||||||
|         return default |         return default | ||||||
|  | 
 | ||||||
|  |     import subprocess | ||||||
|     try: |     try: | ||||||
|         f = os.popen('uname %s 2> %s' % (option, DEV_NULL)) |         output = subprocess.check_output(('uname', option), | ||||||
|     except (AttributeError, OSError): |                                          stderr=subprocess.DEVNULL, | ||||||
|  |                                          text=True) | ||||||
|  |     except (OSError, subprocess.CalledProcessError): | ||||||
|         return default |         return default | ||||||
|     output = f.read().strip() |     return (output.strip() or default) | ||||||
|     rc = f.close() |  | ||||||
|     if not output or rc: |  | ||||||
|         return default |  | ||||||
|     else: |  | ||||||
|         return output |  | ||||||
| 
 | 
 | ||||||
| def _syscmd_file(target, default=''): | def _syscmd_file(target, default=''): | ||||||
| 
 | 
 | ||||||
|  | @ -629,17 +614,12 @@ def _syscmd_file(target, default=''): | ||||||
|     import subprocess |     import subprocess | ||||||
|     target = _follow_symlinks(target) |     target = _follow_symlinks(target) | ||||||
|     try: |     try: | ||||||
|         proc = subprocess.Popen(['file', target], |         output = subprocess.check_output(['file', target], | ||||||
|                                 stdout=subprocess.PIPE, |                                          stderr=subprocess.DEVNULL, | ||||||
|                                 stderr=subprocess.STDOUT) |                                          encoding='latin-1') | ||||||
|     except (AttributeError, OSError): |     except (OSError, subprocess.CalledProcessError): | ||||||
|         return default |         return default | ||||||
|     output = proc.communicate()[0].decode('latin-1') |     return (output or default) | ||||||
|     rc = proc.wait() |  | ||||||
|     if not output or rc: |  | ||||||
|         return default |  | ||||||
|     else: |  | ||||||
|         return output |  | ||||||
| 
 | 
 | ||||||
| ### Information about the used architecture | ### Information about the used architecture | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -222,16 +222,16 @@ def test_mac_ver(self): | ||||||
|         res = platform.mac_ver() |         res = platform.mac_ver() | ||||||
| 
 | 
 | ||||||
|         if platform.uname().system == 'Darwin': |         if platform.uname().system == 'Darwin': | ||||||
|             # We're on a MacOSX system, check that |             # We are on a macOS system, check that the right version | ||||||
|             # the right version information is returned |             # information is returned | ||||||
|             fd = os.popen('sw_vers', 'r') |             output = subprocess.check_output(['sw_vers'], text=True) | ||||||
|             real_ver = None |             for line in output.splitlines(): | ||||||
|             for ln in fd: |                 if line.startswith('ProductVersion:'): | ||||||
|                 if ln.startswith('ProductVersion:'): |                     real_ver = line.strip().split()[-1] | ||||||
|                     real_ver = ln.strip().split()[-1] |  | ||||||
|                     break |                     break | ||||||
|             fd.close() |             else: | ||||||
|             self.assertFalse(real_ver is None) |                 self.fail(f"failed to parse sw_vers output: {output!r}") | ||||||
|  | 
 | ||||||
|             result_list = res[0].split('.') |             result_list = res[0].split('.') | ||||||
|             expect_list = real_ver.split('.') |             expect_list = real_ver.split('.') | ||||||
|             len_diff = len(result_list) - len(expect_list) |             len_diff = len(result_list) - len(expect_list) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | :func:`platform.uname` now redirects ``stderr`` to :data:`os.devnull` when | ||||||
|  | running external programs like ``cmd /c ver``. | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner