1 from unittest import mock 2 import os 3 import platform 4 import subprocess 5 import sys 6 import sysconfig 7 import tempfile 8 import unittest 9 import warnings 10 11 from test import support 12 13 class PlatformTest(unittest.TestCase): 14 def test_architecture(self): 15 res = platform.architecture() 16 17 @support.skip_unless_symlink 18 def test_architecture_via_symlink(self): # issue3762 19 # On Windows, the EXE needs to know where pythonXY.dll and *.pyd is at 20 # so we add the directory to the path, PYTHONHOME and PYTHONPATH. 21 env = None 22 if sys.platform == "win32": 23 env = {k.upper(): os.environ[k] for k in os.environ} 24 env["PATH"] = "{};{}".format( 25 os.path.dirname(sys.executable), env.get("PATH", "")) 26 env["PYTHONHOME"] = os.path.dirname(sys.executable) 27 if sysconfig.is_python_build(True): 28 env["PYTHONPATH"] = os.path.dirname(os.__file__) 29 30 def get(python, env=None): 31 cmd = [python, '-c', 32 'import platform; print(platform.architecture())'] 33 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 34 stderr=subprocess.PIPE, env=env) 35 r = p.communicate() 36 if p.returncode: 37 print(repr(r[0])) 38 print(repr(r[1]), file=sys.stderr) 39 self.fail('unexpected return code: {0} (0x{0:08X})' 40 .format(p.returncode)) 41 return r 42 43 real = os.path.realpath(sys.executable) 44 link = os.path.abspath(support.TESTFN) 45 os.symlink(real, link) 46 try: 47 self.assertEqual(get(real), get(link, env=env)) 48 finally: 49 os.remove(link) 50 51 def test_platform(self): 52 for aliased in (False, True): 53 for terse in (False, True): 54 res = platform.platform(aliased, terse) 55 56 def test_system(self): 57 res = platform.system() 58 59 def test_node(self): 60 res = platform.node() 61 62 def test_release(self): 63 res = platform.release() 64 65 def test_version(self): 66 res = platform.version() 67 68 def test_machine(self): 69 res = platform.machine() 70 71 def test_processor(self): 72 res = platform.processor() 73 74 def setUp(self): 75 self.save_version = sys.version 76 self.save_git = sys._git 77 self.save_platform = sys.platform 78 79 def tearDown(self): 80 sys.version = self.save_version 81 sys._git = self.save_git 82 sys.platform = self.save_platform 83 84 def test_sys_version(self): 85 # Old test. 86 for input, output in ( 87 ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]', 88 ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')), 89 ('IronPython 1.0.60816 on .NET 2.0.50727.42', 90 ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')), 91 ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42', 92 ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')), 93 ('2.4.3 (truncation, date, t) \n[GCC]', 94 ('CPython', '2.4.3', '', '', 'truncation', 'date t', 'GCC')), 95 ('2.4.3 (truncation, date, ) \n[GCC]', 96 ('CPython', '2.4.3', '', '', 'truncation', 'date', 'GCC')), 97 ('2.4.3 (truncation, date,) \n[GCC]', 98 ('CPython', '2.4.3', '', '', 'truncation', 'date', 'GCC')), 99 ('2.4.3 (truncation, date) \n[GCC]', 100 ('CPython', '2.4.3', '', '', 'truncation', 'date', 'GCC')), 101 ('2.4.3 (truncation, d) \n[GCC]', 102 ('CPython', '2.4.3', '', '', 'truncation', 'd', 'GCC')), 103 ('2.4.3 (truncation, ) \n[GCC]', 104 ('CPython', '2.4.3', '', '', 'truncation', '', 'GCC')), 105 ('2.4.3 (truncation,) \n[GCC]', 106 ('CPython', '2.4.3', '', '', 'truncation', '', 'GCC')), 107 ('2.4.3 (truncation) \n[GCC]', 108 ('CPython', '2.4.3', '', '', 'truncation', '', 'GCC')), 109 ): 110 # branch and revision are not "parsed", but fetched 111 # from sys._git. Ignore them 112 (name, version, branch, revision, buildno, builddate, compiler) \ 113 = platform._sys_version(input) 114 self.assertEqual( 115 (name, version, '', '', buildno, builddate, compiler), output) 116 117 # Tests for python_implementation(), python_version(), python_branch(), 118 # python_revision(), python_build(), and python_compiler(). 119 sys_versions = { 120 ("2.6.1 (r261:67515, Dec 6 2008, 15:26:00) \n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]", 121 ('CPython', 'tags/r261', '67515'), self.save_platform) 122 : 123 ("CPython", "2.6.1", "tags/r261", "67515", 124 ('r261:67515', 'Dec 6 2008 15:26:00'), 125 'GCC 4.0.1 (Apple Computer, Inc. build 5370)'), 126 127 ("IronPython 2.0 (2.0.0.0) on .NET 2.0.50727.3053", None, "cli") 128 : 129 ("IronPython", "2.0.0", "", "", ("", ""), 130 ".NET 2.0.50727.3053"), 131 132 ("2.6.1 (IronPython 2.6.1 (2.6.10920.0) on .NET 2.0.50727.1433)", None, "cli") 133 : 134 ("IronPython", "2.6.1", "", "", ("", ""), 135 ".NET 2.0.50727.1433"), 136 137 ("2.7.4 (IronPython 2.7.4 (2.7.0.40) on Mono 4.0.30319.1 (32-bit))", None, "cli") 138 : 139 ("IronPython", "2.7.4", "", "", ("", ""), 140 "Mono 4.0.30319.1 (32-bit)"), 141 142 ("2.5 (trunk:6107, Mar 26 2009, 13:02:18) \n[Java HotSpot(TM) Client VM (\"Apple Computer, Inc.\")]", 143 ('Jython', 'trunk', '6107'), "java1.5.0_16") 144 : 145 ("Jython", "2.5.0", "trunk", "6107", 146 ('trunk:6107', 'Mar 26 2009'), "java1.5.0_16"), 147 148 ("2.5.2 (63378, Mar 26 2009, 18:03:29)\n[PyPy 1.0.0]", 149 ('PyPy', 'trunk', '63378'), self.save_platform) 150 : 151 ("PyPy", "2.5.2", "trunk", "63378", ('63378', 'Mar 26 2009'), 152 "") 153 } 154 for (version_tag, scm, sys_platform), info in \ 155 sys_versions.items(): 156 sys.version = version_tag 157 if scm is None: 158 if hasattr(sys, "_git"): 159 del sys._git 160 else: 161 sys._git = scm 162 if sys_platform is not None: 163 sys.platform = sys_platform 164 self.assertEqual(platform.python_implementation(), info[0]) 165 self.assertEqual(platform.python_version(), info[1]) 166 self.assertEqual(platform.python_branch(), info[2]) 167 self.assertEqual(platform.python_revision(), info[3]) 168 self.assertEqual(platform.python_build(), info[4]) 169 self.assertEqual(platform.python_compiler(), info[5]) 170 171 def test_system_alias(self): 172 res = platform.system_alias( 173 platform.system(), 174 platform.release(), 175 platform.version(), 176 ) 177 178 def test_uname(self): 179 res = platform.uname() 180 self.assertTrue(any(res)) 181 self.assertEqual(res[0], res.system) 182 self.assertEqual(res[1], res.node) 183 self.assertEqual(res[2], res.release) 184 self.assertEqual(res[3], res.version) 185 self.assertEqual(res[4], res.machine) 186 self.assertEqual(res[5], res.processor) 187 188 @unittest.skipUnless(sys.platform.startswith('win'), "windows only test") 189 def test_uname_win32_ARCHITEW6432(self): 190 # Issue 7860: make sure we get architecture from the correct variable 191 # on 64 bit Windows: if PROCESSOR_ARCHITEW6432 exists we should be 192 # using it, per 193 # http://blogs.msdn.com/david.wang/archive/2006/03/26/HOWTO-Detect-Process-Bitness.aspx 194 try: 195 with support.EnvironmentVarGuard() as environ: 196 if 'PROCESSOR_ARCHITEW6432' in environ: 197 del environ['PROCESSOR_ARCHITEW6432'] 198 environ['PROCESSOR_ARCHITECTURE'] = 'foo' 199 platform._uname_cache = None 200 system, node, release, version, machine, processor = platform.uname() 201 self.assertEqual(machine, 'foo') 202 environ['PROCESSOR_ARCHITEW6432'] = 'bar' 203 platform._uname_cache = None 204 system, node, release, version, machine, processor = platform.uname() 205 self.assertEqual(machine, 'bar') 206 finally: 207 platform._uname_cache = None 208 209 def test_java_ver(self): 210 res = platform.java_ver() 211 if sys.platform == 'java': 212 self.assertTrue(all(res)) 213 214 def test_win32_ver(self): 215 res = platform.win32_ver() 216 217 def test_mac_ver(self): 218 res = platform.mac_ver() 219 220 if platform.uname().system == 'Darwin': 221 # We're on a MacOSX system, check that 222 # the right version information is returned 223 fd = os.popen('sw_vers', 'r') 224 real_ver = None 225 for ln in fd: 226 if ln.startswith('ProductVersion:'): 227 real_ver = ln.strip().split()[-1] 228 break 229 fd.close() 230 self.assertFalse(real_ver is None) 231 result_list = res[0].split('.') 232 expect_list = real_ver.split('.') 233 len_diff = len(result_list) - len(expect_list) 234 # On Snow Leopard, sw_vers reports 10.6.0 as 10.6 235 if len_diff > 0: 236 expect_list.extend(['0'] * len_diff) 237 self.assertEqual(result_list, expect_list) 238 239 # res[1] claims to contain 240 # (version, dev_stage, non_release_version) 241 # That information is no longer available 242 self.assertEqual(res[1], ('', '', '')) 243 244 if sys.byteorder == 'little': 245 self.assertIn(res[2], ('i386', 'x86_64')) 246 else: 247 self.assertEqual(res[2], 'PowerPC') 248 249 250 @unittest.skipUnless(sys.platform == 'darwin', "OSX only test") 251 def test_mac_ver_with_fork(self): 252 # Issue7895: platform.mac_ver() crashes when using fork without exec 253 # 254 # This test checks that the fix for that issue works. 255 # 256 pid = os.fork() 257 if pid == 0: 258 # child 259 info = platform.mac_ver() 260 os._exit(0) 261 262 else: 263 # parent 264 cpid, sts = os.waitpid(pid, 0) 265 self.assertEqual(cpid, pid) 266 self.assertEqual(sts, 0) 267 268 def test_dist(self): 269 with warnings.catch_warnings(): 270 warnings.filterwarnings( 271 'ignore', 272 r'dist\(\) and linux_distribution\(\) ' 273 'functions are deprecated .*', 274 DeprecationWarning, 275 ) 276 res = platform.dist() 277 278 def test_libc_ver(self): 279 if os.path.isdir(sys.executable) and \ 280 os.path.exists(sys.executable+'.exe'): 281 # Cygwin horror 282 executable = sys.executable + '.exe' 283 else: 284 executable = sys.executable 285 res = platform.libc_ver(executable) 286 287 self.addCleanup(support.unlink, support.TESTFN) 288 with open(support.TESTFN, 'wb') as f: 289 f.write(b'x'*(16384-10)) 290 f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0') 291 self.assertEqual(platform.libc_ver(support.TESTFN), 292 ('glibc', '1.23.4')) 293 294 @support.cpython_only 295 def test__comparable_version(self): 296 from platform import _comparable_version as V 297 self.assertEqual(V('1.2.3'), V('1.2.3')) 298 self.assertLess(V('1.2.3'), V('1.2.10')) 299 self.assertEqual(V('1.2.3.4'), V('1_2-3+4')) 300 self.assertLess(V('1.2spam'), V('1.2dev')) 301 self.assertLess(V('1.2dev'), V('1.2alpha')) 302 self.assertLess(V('1.2dev'), V('1.2a')) 303 self.assertLess(V('1.2alpha'), V('1.2beta')) 304 self.assertLess(V('1.2a'), V('1.2b')) 305 self.assertLess(V('1.2beta'), V('1.2c')) 306 self.assertLess(V('1.2b'), V('1.2c')) 307 self.assertLess(V('1.2c'), V('1.2RC')) 308 self.assertLess(V('1.2c'), V('1.2rc')) 309 self.assertLess(V('1.2RC'), V('1.2.0')) 310 self.assertLess(V('1.2rc'), V('1.2.0')) 311 self.assertLess(V('1.2.0'), V('1.2pl')) 312 self.assertLess(V('1.2.0'), V('1.2p')) 313 314 self.assertLess(V('1.5.1'), V('1.5.2b2')) 315 self.assertLess(V('3.10a'), V('161')) 316 self.assertEqual(V('8.02'), V('8.02')) 317 self.assertLess(V('3.4j'), V('1996.07.12')) 318 self.assertLess(V('3.1.1.6'), V('3.2.pl0')) 319 self.assertLess(V('2g6'), V('11g')) 320 self.assertLess(V('0.9'), V('2.2')) 321 self.assertLess(V('1.2'), V('1.2.1')) 322 self.assertLess(V('1.1'), V('1.2.2')) 323 self.assertLess(V('1.1'), V('1.2')) 324 self.assertLess(V('1.2.1'), V('1.2.2')) 325 self.assertLess(V('1.2'), V('1.2.2')) 326 self.assertLess(V('0.4'), V('0.4.0')) 327 self.assertLess(V('1.13++'), V('5.5.kw')) 328 self.assertLess(V('0.960923'), V('2.2beta29')) 329 330 def test_parse_release_file(self): 331 332 for input, output in ( 333 # Examples of release file contents: 334 ('SuSE Linux 9.3 (x86-64)', ('SuSE Linux ', '9.3', 'x86-64')), 335 ('SUSE LINUX 10.1 (X86-64)', ('SUSE LINUX ', '10.1', 'X86-64')), 336 ('SUSE LINUX 10.1 (i586)', ('SUSE LINUX ', '10.1', 'i586')), 337 ('Fedora Core release 5 (Bordeaux)', ('Fedora Core', '5', 'Bordeaux')), 338 ('Red Hat Linux release 8.0 (Psyche)', ('Red Hat Linux', '8.0', 'Psyche')), 339 ('Red Hat Linux release 9 (Shrike)', ('Red Hat Linux', '9', 'Shrike')), 340 ('Red Hat Enterprise Linux release 4 (Nahant)', ('Red Hat Enterprise Linux', '4', 'Nahant')), 341 ('CentOS release 4', ('CentOS', '4', None)), 342 ('Rocks release 4.2.1 (Cydonia)', ('Rocks', '4.2.1', 'Cydonia')), 343 ('', ('', '', '')), # If there's nothing there. 344 ): 345 self.assertEqual(platform._parse_release_file(input), output) 346 347 def test_popen(self): 348 mswindows = (sys.platform == "win32") 349 350 if mswindows: 351 command = '"{}" -c "print(\'Hello\')"'.format(sys.executable) 352 else: 353 command = "'{}' -c 'print(\"Hello\")'".format(sys.executable) 354 with warnings.catch_warnings(): 355 warnings.simplefilter("ignore", DeprecationWarning) 356 with platform.popen(command) as stdout: 357 hello = stdout.read().strip() 358 stdout.close() 359 self.assertEqual(hello, "Hello") 360 361 data = 'plop' 362 if mswindows: 363 command = '"{}" -c "import sys; data=sys.stdin.read(); exit(len(data))"' 364 else: 365 command = "'{}' -c 'import sys; data=sys.stdin.read(); exit(len(data))'" 366 command = command.format(sys.executable) 367 with warnings.catch_warnings(): 368 warnings.simplefilter("ignore", DeprecationWarning) 369 with platform.popen(command, 'w') as stdin: 370 stdout = stdin.write(data) 371 ret = stdin.close() 372 self.assertIsNotNone(ret) 373 if os.name == 'nt': 374 returncode = ret 375 else: 376 returncode = ret >> 8 377 self.assertEqual(returncode, len(data)) 378 379 def test_linux_distribution_encoding(self): 380 # Issue #17429 381 with tempfile.TemporaryDirectory() as tempdir: 382 filename = os.path.join(tempdir, 'fedora-release') 383 with open(filename, 'w', encoding='utf-8') as f: 384 f.write('Fedora release 19 (Schr\xf6dinger\u2019s Cat)\n') 385 386 with mock.patch('platform._UNIXCONFDIR', tempdir): 387 with warnings.catch_warnings(): 388 warnings.filterwarnings( 389 'ignore', 390 r'dist\(\) and linux_distribution\(\) ' 391 'functions are deprecated .*', 392 DeprecationWarning, 393 ) 394 distname, version, distid = platform.linux_distribution() 395 396 self.assertEqual(distname, 'Fedora') 397 self.assertEqual(version, '19') 398 self.assertEqual(distid, 'Schr\xf6dinger\u2019s Cat') 399 400 401 class DeprecationTest(unittest.TestCase): 402 403 def test_dist_deprecation(self): 404 with self.assertWarns(DeprecationWarning) as cm: 405 platform.dist() 406 self.assertEqual(str(cm.warning), 407 'dist() and linux_distribution() functions are ' 408 'deprecated in Python 3.5') 409 410 def test_linux_distribution_deprecation(self): 411 with self.assertWarns(DeprecationWarning) as cm: 412 platform.linux_distribution() 413 self.assertEqual(str(cm.warning), 414 'dist() and linux_distribution() functions are ' 415 'deprecated in Python 3.5') 416 417 if __name__ == '__main__': 418 unittest.main() 419