| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- import os
- import copy
- import pickle
- import platform
- import subprocess
- import sys
- import unittest
- from unittest import mock
- from test import support
- from test.support import os_helper
- FEDORA_OS_RELEASE = """\
- NAME=Fedora
- VERSION="32 (Thirty Two)"
- ID=fedora
- VERSION_ID=32
- VERSION_CODENAME=""
- PLATFORM_ID="platform:f32"
- PRETTY_NAME="Fedora 32 (Thirty Two)"
- ANSI_COLOR="0;34"
- LOGO=fedora-logo-icon
- CPE_NAME="cpe:/o:fedoraproject:fedora:32"
- HOME_URL="https://fedoraproject.org/"
- DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f32/system-administrators-guide/"
- SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help"
- BUG_REPORT_URL="https://bugzilla.redhat.com/"
- REDHAT_BUGZILLA_PRODUCT="Fedora"
- REDHAT_BUGZILLA_PRODUCT_VERSION=32
- REDHAT_SUPPORT_PRODUCT="Fedora"
- REDHAT_SUPPORT_PRODUCT_VERSION=32
- PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"
- """
- UBUNTU_OS_RELEASE = """\
- NAME="Ubuntu"
- VERSION="20.04.1 LTS (Focal Fossa)"
- ID=ubuntu
- ID_LIKE=debian
- PRETTY_NAME="Ubuntu 20.04.1 LTS"
- VERSION_ID="20.04"
- HOME_URL="https://www.ubuntu.com/"
- SUPPORT_URL="https://help.ubuntu.com/"
- BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
- PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
- VERSION_CODENAME=focal
- UBUNTU_CODENAME=focal
- """
- TEST_OS_RELEASE = r"""
- # test data
- ID_LIKE="egg spam viking"
- EMPTY=
- # comments and empty lines are ignored
- SINGLE_QUOTE='single'
- EMPTY_SINGLE=''
- DOUBLE_QUOTE="double"
- EMPTY_DOUBLE=""
- QUOTES="double\'s"
- SPECIALS="\$\`\\\'\""
- # invalid lines
- =invalid
- =
- INVALID
- IN-VALID=value
- IN VALID=value
- """
- class PlatformTest(unittest.TestCase):
- def clear_caches(self):
- platform._platform_cache.clear()
- platform._sys_version_cache.clear()
- platform._uname_cache = None
- platform._os_release_cache = None
- def test_architecture(self):
- res = platform.architecture()
- @os_helper.skip_unless_symlink
- @support.requires_subprocess()
- def test_architecture_via_symlink(self): # issue3762
- with support.PythonSymlink() as py:
- cmd = "-c", "import platform; print(platform.architecture())"
- self.assertEqual(py.call_real(*cmd), py.call_link(*cmd))
- def test_platform(self):
- for aliased in (False, True):
- for terse in (False, True):
- res = platform.platform(aliased, terse)
- def test_system(self):
- res = platform.system()
- def test_node(self):
- res = platform.node()
- def test_release(self):
- res = platform.release()
- def test_version(self):
- res = platform.version()
- def test_machine(self):
- res = platform.machine()
- def test_processor(self):
- res = platform.processor()
- def setUp(self):
- self.save_version = sys.version
- self.save_git = sys._git
- self.save_platform = sys.platform
- def tearDown(self):
- sys.version = self.save_version
- sys._git = self.save_git
- sys.platform = self.save_platform
- def test_sys_version(self):
- # Old test.
- for input, output in (
- ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]',
- ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')),
- ('IronPython 1.0.60816 on .NET 2.0.50727.42',
- ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')),
- ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42',
- ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')),
- ('2.4.3 (truncation, date, t) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', 'date t', 'GCC')),
- ('2.4.3 (truncation, date, ) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', 'date', 'GCC')),
- ('2.4.3 (truncation, date,) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', 'date', 'GCC')),
- ('2.4.3 (truncation, date) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', 'date', 'GCC')),
- ('2.4.3 (truncation, d) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', 'd', 'GCC')),
- ('2.4.3 (truncation, ) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', '', 'GCC')),
- ('2.4.3 (truncation,) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', '', 'GCC')),
- ('2.4.3 (truncation) \n[GCC]',
- ('CPython', '2.4.3', '', '', 'truncation', '', 'GCC')),
- ):
- # branch and revision are not "parsed", but fetched
- # from sys._git. Ignore them
- (name, version, branch, revision, buildno, builddate, compiler) \
- = platform._sys_version(input)
- self.assertEqual(
- (name, version, '', '', buildno, builddate, compiler), output)
- # Tests for python_implementation(), python_version(), python_branch(),
- # python_revision(), python_build(), and python_compiler().
- sys_versions = {
- ("2.6.1 (r261:67515, Dec 6 2008, 15:26:00) \n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]",
- ('CPython', 'tags/r261', '67515'), self.save_platform)
- :
- ("CPython", "2.6.1", "tags/r261", "67515",
- ('r261:67515', 'Dec 6 2008 15:26:00'),
- 'GCC 4.0.1 (Apple Computer, Inc. build 5370)'),
- ("IronPython 2.0 (2.0.0.0) on .NET 2.0.50727.3053", None, "cli")
- :
- ("IronPython", "2.0.0", "", "", ("", ""),
- ".NET 2.0.50727.3053"),
- ("2.6.1 (IronPython 2.6.1 (2.6.10920.0) on .NET 2.0.50727.1433)", None, "cli")
- :
- ("IronPython", "2.6.1", "", "", ("", ""),
- ".NET 2.0.50727.1433"),
- ("2.7.4 (IronPython 2.7.4 (2.7.0.40) on Mono 4.0.30319.1 (32-bit))", None, "cli")
- :
- ("IronPython", "2.7.4", "", "", ("", ""),
- "Mono 4.0.30319.1 (32-bit)"),
- ("2.5 (trunk:6107, Mar 26 2009, 13:02:18) \n[Java HotSpot(TM) Client VM (\"Apple Computer, Inc.\")]",
- ('Jython', 'trunk', '6107'), "java1.5.0_16")
- :
- ("Jython", "2.5.0", "trunk", "6107",
- ('trunk:6107', 'Mar 26 2009'), "java1.5.0_16"),
- ("2.5.2 (63378, Mar 26 2009, 18:03:29)\n[PyPy 1.0.0]",
- ('PyPy', 'trunk', '63378'), self.save_platform)
- :
- ("PyPy", "2.5.2", "trunk", "63378", ('63378', 'Mar 26 2009'),
- "")
- }
- for (version_tag, scm, sys_platform), info in \
- sys_versions.items():
- sys.version = version_tag
- if scm is None:
- if hasattr(sys, "_git"):
- del sys._git
- else:
- sys._git = scm
- if sys_platform is not None:
- sys.platform = sys_platform
- self.assertEqual(platform.python_implementation(), info[0])
- self.assertEqual(platform.python_version(), info[1])
- self.assertEqual(platform.python_branch(), info[2])
- self.assertEqual(platform.python_revision(), info[3])
- self.assertEqual(platform.python_build(), info[4])
- self.assertEqual(platform.python_compiler(), info[5])
- def test_system_alias(self):
- res = platform.system_alias(
- platform.system(),
- platform.release(),
- platform.version(),
- )
- def test_uname(self):
- res = platform.uname()
- self.assertTrue(any(res))
- self.assertEqual(res[0], res.system)
- self.assertEqual(res[-6], res.system)
- self.assertEqual(res[1], res.node)
- self.assertEqual(res[-5], res.node)
- self.assertEqual(res[2], res.release)
- self.assertEqual(res[-4], res.release)
- self.assertEqual(res[3], res.version)
- self.assertEqual(res[-3], res.version)
- self.assertEqual(res[4], res.machine)
- self.assertEqual(res[-2], res.machine)
- self.assertEqual(res[5], res.processor)
- self.assertEqual(res[-1], res.processor)
- self.assertEqual(len(res), 6)
- def test_uname_cast_to_tuple(self):
- res = platform.uname()
- expected = (
- res.system, res.node, res.release, res.version, res.machine,
- res.processor,
- )
- self.assertEqual(tuple(res), expected)
- def test_uname_replace(self):
- res = platform.uname()
- new = res._replace(
- system='system', node='node', release='release',
- version='version', machine='machine')
- self.assertEqual(new.system, 'system')
- self.assertEqual(new.node, 'node')
- self.assertEqual(new.release, 'release')
- self.assertEqual(new.version, 'version')
- self.assertEqual(new.machine, 'machine')
- # processor cannot be replaced
- self.assertEqual(new.processor, res.processor)
- def test_uname_copy(self):
- uname = platform.uname()
- self.assertEqual(copy.copy(uname), uname)
- self.assertEqual(copy.deepcopy(uname), uname)
- def test_uname_pickle(self):
- orig = platform.uname()
- for proto in range(pickle.HIGHEST_PROTOCOL + 1):
- with self.subTest(protocol=proto):
- pickled = pickle.dumps(orig, proto)
- restored = pickle.loads(pickled)
- self.assertEqual(restored, orig)
- def test_uname_slices(self):
- res = platform.uname()
- expected = tuple(res)
- self.assertEqual(res[:], expected)
- self.assertEqual(res[:5], expected[:5])
- def test_uname_fields(self):
- self.assertIn('processor', platform.uname()._fields)
- def test_uname_asdict(self):
- res = platform.uname()._asdict()
- self.assertEqual(len(res), 6)
- self.assertIn('processor', res)
- @unittest.skipIf(sys.platform in ['win32', 'OpenVMS'], "uname -p not used")
- @support.requires_subprocess()
- def test_uname_processor(self):
- """
- On some systems, the processor must match the output
- of 'uname -p'. See Issue 35967 for rationale.
- """
- try:
- proc_res = subprocess.check_output(['uname', '-p'], text=True).strip()
- expect = platform._unknown_as_blank(proc_res)
- except (OSError, subprocess.CalledProcessError):
- expect = ''
- self.assertEqual(platform.uname().processor, expect)
- @unittest.skipUnless(sys.platform.startswith('win'), "windows only test")
- def test_uname_win32_ARCHITEW6432(self):
- # Issue 7860: make sure we get architecture from the correct variable
- # on 64 bit Windows: if PROCESSOR_ARCHITEW6432 exists we should be
- # using it, per
- # http://blogs.msdn.com/david.wang/archive/2006/03/26/HOWTO-Detect-Process-Bitness.aspx
- try:
- with os_helper.EnvironmentVarGuard() as environ:
- if 'PROCESSOR_ARCHITEW6432' in environ:
- del environ['PROCESSOR_ARCHITEW6432']
- environ['PROCESSOR_ARCHITECTURE'] = 'foo'
- platform._uname_cache = None
- system, node, release, version, machine, processor = platform.uname()
- self.assertEqual(machine, 'foo')
- environ['PROCESSOR_ARCHITEW6432'] = 'bar'
- platform._uname_cache = None
- system, node, release, version, machine, processor = platform.uname()
- self.assertEqual(machine, 'bar')
- finally:
- platform._uname_cache = None
- def test_java_ver(self):
- res = platform.java_ver()
- if sys.platform == 'java':
- self.assertTrue(all(res))
- def test_win32_ver(self):
- res = platform.win32_ver()
- def test_mac_ver(self):
- res = platform.mac_ver()
- if platform.uname().system == 'Darwin':
- # We are on a macOS system, check that the right version
- # information is returned
- output = subprocess.check_output(['sw_vers'], text=True)
- for line in output.splitlines():
- if line.startswith('ProductVersion:'):
- real_ver = line.strip().split()[-1]
- break
- else:
- self.fail(f"failed to parse sw_vers output: {output!r}")
- result_list = res[0].split('.')
- expect_list = real_ver.split('.')
- len_diff = len(result_list) - len(expect_list)
- # On Snow Leopard, sw_vers reports 10.6.0 as 10.6
- if len_diff > 0:
- expect_list.extend(['0'] * len_diff)
- # For compatibility with older binaries, macOS 11.x may report
- # itself as '10.16' rather than '11.x.y'.
- if result_list != ['10', '16']:
- self.assertEqual(result_list, expect_list)
- # res[1] claims to contain
- # (version, dev_stage, non_release_version)
- # That information is no longer available
- self.assertEqual(res[1], ('', '', ''))
- if sys.byteorder == 'little':
- self.assertIn(res[2], ('i386', 'x86_64', 'arm64'))
- else:
- self.assertEqual(res[2], 'PowerPC')
- @unittest.skipUnless(sys.platform == 'darwin', "OSX only test")
- def test_mac_ver_with_fork(self):
- # Issue7895: platform.mac_ver() crashes when using fork without exec
- #
- # This test checks that the fix for that issue works.
- #
- pid = os.fork()
- if pid == 0:
- # child
- info = platform.mac_ver()
- os._exit(0)
- else:
- # parent
- support.wait_process(pid, exitcode=0)
- @unittest.skipIf(support.is_emscripten, "Does not apply to Emscripten")
- def test_libc_ver(self):
- # check that libc_ver(executable) doesn't raise an exception
- if os.path.isdir(sys.executable) and \
- os.path.exists(sys.executable+'.exe'):
- # Cygwin horror
- executable = sys.executable + '.exe'
- elif sys.platform == "win32" and not os.path.exists(sys.executable):
- # App symlink appears to not exist, but we want the
- # real executable here anyway
- import _winapi
- executable = _winapi.GetModuleFileName(0)
- else:
- executable = sys.executable
- platform.libc_ver(executable)
- filename = os_helper.TESTFN
- self.addCleanup(os_helper.unlink, filename)
- with mock.patch('os.confstr', create=True, return_value='mock 1.0'):
- # test os.confstr() code path
- self.assertEqual(platform.libc_ver(), ('mock', '1.0'))
- # test the different regular expressions
- for data, expected in (
- (b'__libc_init', ('libc', '')),
- (b'GLIBC_2.9', ('glibc', '2.9')),
- (b'libc.so.1.2.5', ('libc', '1.2.5')),
- (b'libc_pthread.so.1.2.5', ('libc', '1.2.5_pthread')),
- (b'', ('', '')),
- ):
- with open(filename, 'wb') as fp:
- fp.write(b'[xxx%sxxx]' % data)
- fp.flush()
- # os.confstr() must not be used if executable is set
- self.assertEqual(platform.libc_ver(executable=filename),
- expected)
- # binary containing multiple versions: get the most recent,
- # make sure that 1.9 is seen as older than 1.23.4
- chunksize = 16384
- with open(filename, 'wb') as f:
- # test match at chunk boundary
- f.write(b'x'*(chunksize - 10))
- f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0')
- self.assertEqual(platform.libc_ver(filename, chunksize=chunksize),
- ('glibc', '1.23.4'))
- @support.cpython_only
- def test__comparable_version(self):
- from platform import _comparable_version as V
- self.assertEqual(V('1.2.3'), V('1.2.3'))
- self.assertLess(V('1.2.3'), V('1.2.10'))
- self.assertEqual(V('1.2.3.4'), V('1_2-3+4'))
- self.assertLess(V('1.2spam'), V('1.2dev'))
- self.assertLess(V('1.2dev'), V('1.2alpha'))
- self.assertLess(V('1.2dev'), V('1.2a'))
- self.assertLess(V('1.2alpha'), V('1.2beta'))
- self.assertLess(V('1.2a'), V('1.2b'))
- self.assertLess(V('1.2beta'), V('1.2c'))
- self.assertLess(V('1.2b'), V('1.2c'))
- self.assertLess(V('1.2c'), V('1.2RC'))
- self.assertLess(V('1.2c'), V('1.2rc'))
- self.assertLess(V('1.2RC'), V('1.2.0'))
- self.assertLess(V('1.2rc'), V('1.2.0'))
- self.assertLess(V('1.2.0'), V('1.2pl'))
- self.assertLess(V('1.2.0'), V('1.2p'))
- self.assertLess(V('1.5.1'), V('1.5.2b2'))
- self.assertLess(V('3.10a'), V('161'))
- self.assertEqual(V('8.02'), V('8.02'))
- self.assertLess(V('3.4j'), V('1996.07.12'))
- self.assertLess(V('3.1.1.6'), V('3.2.pl0'))
- self.assertLess(V('2g6'), V('11g'))
- self.assertLess(V('0.9'), V('2.2'))
- self.assertLess(V('1.2'), V('1.2.1'))
- self.assertLess(V('1.1'), V('1.2.2'))
- self.assertLess(V('1.1'), V('1.2'))
- self.assertLess(V('1.2.1'), V('1.2.2'))
- self.assertLess(V('1.2'), V('1.2.2'))
- self.assertLess(V('0.4'), V('0.4.0'))
- self.assertLess(V('1.13++'), V('5.5.kw'))
- self.assertLess(V('0.960923'), V('2.2beta29'))
- def test_macos(self):
- self.addCleanup(self.clear_caches)
- uname = ('Darwin', 'hostname', '17.7.0',
- ('Darwin Kernel Version 17.7.0: '
- 'Thu Jun 21 22:53:14 PDT 2018; '
- 'root:xnu-4570.71.2~1/RELEASE_X86_64'),
- 'x86_64', 'i386')
- arch = ('64bit', '')
- with mock.patch.object(platform, 'uname', return_value=uname), \
- mock.patch.object(platform, 'architecture', return_value=arch):
- for mac_ver, expected_terse, expected in [
- # darwin: mac_ver() returns empty strings
- (('', '', ''),
- 'Darwin-17.7.0',
- 'Darwin-17.7.0-x86_64-i386-64bit'),
- # macOS: mac_ver() returns macOS version
- (('10.13.6', ('', '', ''), 'x86_64'),
- 'macOS-10.13.6',
- 'macOS-10.13.6-x86_64-i386-64bit'),
- ]:
- with mock.patch.object(platform, 'mac_ver',
- return_value=mac_ver):
- self.clear_caches()
- self.assertEqual(platform.platform(terse=1), expected_terse)
- self.assertEqual(platform.platform(), expected)
- def test_freedesktop_os_release(self):
- self.addCleanup(self.clear_caches)
- self.clear_caches()
- if any(os.path.isfile(fn) for fn in platform._os_release_candidates):
- info = platform.freedesktop_os_release()
- self.assertIn("NAME", info)
- self.assertIn("ID", info)
- info["CPYTHON_TEST"] = "test"
- self.assertNotIn(
- "CPYTHON_TEST",
- platform.freedesktop_os_release()
- )
- else:
- with self.assertRaises(OSError):
- platform.freedesktop_os_release()
- def test_parse_os_release(self):
- info = platform._parse_os_release(FEDORA_OS_RELEASE.splitlines())
- self.assertEqual(info["NAME"], "Fedora")
- self.assertEqual(info["ID"], "fedora")
- self.assertNotIn("ID_LIKE", info)
- self.assertEqual(info["VERSION_CODENAME"], "")
- info = platform._parse_os_release(UBUNTU_OS_RELEASE.splitlines())
- self.assertEqual(info["NAME"], "Ubuntu")
- self.assertEqual(info["ID"], "ubuntu")
- self.assertEqual(info["ID_LIKE"], "debian")
- self.assertEqual(info["VERSION_CODENAME"], "focal")
- info = platform._parse_os_release(TEST_OS_RELEASE.splitlines())
- expected = {
- "ID": "linux",
- "NAME": "Linux",
- "PRETTY_NAME": "Linux",
- "ID_LIKE": "egg spam viking",
- "EMPTY": "",
- "DOUBLE_QUOTE": "double",
- "EMPTY_DOUBLE": "",
- "SINGLE_QUOTE": "single",
- "EMPTY_SINGLE": "",
- "QUOTES": "double's",
- "SPECIALS": "$`\\'\"",
- }
- self.assertEqual(info, expected)
- self.assertEqual(len(info["SPECIALS"]), 5)
- if __name__ == '__main__':
- unittest.main()
|