Skip to content

Commit 872c071

Browse files
gh-71052: Change Android's sys.platform from "linux" to "android"
Co-authored-by: Erlend E. Aasland <[email protected]>
1 parent 9f983e0 commit 872c071

24 files changed

+94
-78
lines changed

Doc/library/sys.rst

+20-25
Original file line numberDiff line numberDiff line change
@@ -1367,47 +1367,42 @@ always available.
13671367

13681368
.. data:: platform
13691369

1370-
This string contains a platform identifier that can be used to append
1371-
platform-specific components to :data:`sys.path`, for instance.
1372-
1373-
For Unix systems, except on Linux and AIX, this is the lowercased OS name as
1374-
returned by ``uname -s`` with the first part of the version as returned by
1375-
``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, *at the time
1376-
when Python was built*. Unless you want to test for a specific system
1377-
version, it is therefore recommended to use the following idiom::
1378-
1379-
if sys.platform.startswith('freebsd'):
1380-
# FreeBSD-specific code here...
1381-
elif sys.platform.startswith('linux'):
1382-
# Linux-specific code here...
1383-
elif sys.platform.startswith('aix'):
1384-
# AIX-specific code here...
1385-
1386-
For other systems, the values are:
1370+
A string containing a platform identifier. Known values are:
13871371

13881372
================ ===========================
13891373
System ``platform`` value
13901374
================ ===========================
13911375
AIX ``'aix'``
1376+
Android ``'android'``
13921377
Emscripten ``'emscripten'``
1378+
iOS ``'ios'``
13931379
Linux ``'linux'``
1394-
WASI ``'wasi'``
1380+
macOS ``'darwin'``
13951381
Windows ``'win32'``
13961382
Windows/Cygwin ``'cygwin'``
1397-
macOS ``'darwin'``
1383+
WASI ``'wasi'``
13981384
================ ===========================
13991385

1386+
On Unix systems not listed in the table, the value is the lowercased OS name
1387+
as returned by ``uname -s``, with the first part of the version as returned by
1388+
``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, *at the time
1389+
when Python was built*. Unless you want to test for a specific system
1390+
version, it is therefore recommended to use the following idiom::
1391+
1392+
if sys.platform.startswith('freebsd'):
1393+
# FreeBSD-specific code here...
1394+
14001395
.. versionchanged:: 3.3
14011396
On Linux, :data:`sys.platform` doesn't contain the major version anymore.
1402-
It is always ``'linux'``, instead of ``'linux2'`` or ``'linux3'``. Since
1403-
older Python versions include the version number, it is recommended to
1404-
always use the ``startswith`` idiom presented above.
1397+
It is always ``'linux'``, instead of ``'linux2'`` or ``'linux3'``.
14051398

14061399
.. versionchanged:: 3.8
14071400
On AIX, :data:`sys.platform` doesn't contain the major version anymore.
1408-
It is always ``'aix'``, instead of ``'aix5'`` or ``'aix7'``. Since
1409-
older Python versions include the version number, it is recommended to
1410-
always use the ``startswith`` idiom presented above.
1401+
It is always ``'aix'``, instead of ``'aix5'`` or ``'aix7'``.
1402+
1403+
.. versionchanged:: 3.13
1404+
On Android, :data:`sys.platform` now returns ``'android'`` rather than
1405+
``'linux'``.
14111406

14121407
.. seealso::
14131408

Lib/ctypes/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ def LoadLibrary(self, name):
468468

469469
if _os.name == "nt":
470470
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
471-
elif hasattr(_sys, "getandroidapilevel"):
471+
elif _sys.platform == "android":
472472
pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2])
473473
elif _sys.platform == "cygwin":
474474
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])

Lib/multiprocessing/util.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,7 @@ def log_to_stderr(level=None):
102102
# Abstract socket support
103103

104104
def _platform_supports_abstract_sockets():
105-
if sys.platform == "linux":
106-
return True
107-
if hasattr(sys, 'getandroidapilevel'):
108-
return True
109-
return False
105+
return sys.platform in ("linux", "android")
110106

111107

112108
def is_abstract_socket_namespace(address):

Lib/shutil.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024
4848
# This should never be removed, see rationale in:
4949
# https://bugs.python.org/issue43743#msg393429
50-
_USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux")
50+
_USE_CP_SENDFILE = (hasattr(os, "sendfile")
51+
and sys.platform.startswith(("linux", "android")))
5152
_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS
5253

5354
# CMD defaults in Windows 10

Lib/test/support/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ def requires_debug_ranges(reason='requires co_positions / debug_ranges'):
520520
# Is not actually used in tests, but is kept for compatibility.
521521
is_jython = sys.platform.startswith('java')
522522

523-
is_android = hasattr(sys, 'getandroidapilevel')
523+
is_android = sys.platform == "android"
524524

525525
if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
526526
unix_shell = '/system/bin/sh' if is_android else '/bin/sh'

Lib/test/support/os_helper.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ def __fspath__(self):
612612
def fd_count():
613613
"""Count the number of open file descriptors.
614614
"""
615-
if sys.platform.startswith(('linux', 'freebsd', 'emscripten')):
615+
if sys.platform.startswith(('linux', 'android', 'freebsd', 'emscripten')):
616616
fd_path = "/proc/self/fd"
617617
elif sys.platform == "darwin":
618618
fd_path = "/dev/fd"

Lib/test/test_asyncio/test_subprocess.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,8 @@ async def empty_error():
480480
self.assertEqual(output, None)
481481
self.assertEqual(exitcode, 0)
482482

483-
@unittest.skipIf(sys.platform != 'linux', "Don't have /dev/stdin")
483+
@unittest.skipIf(sys.platform not in ('linux', 'android'),
484+
"Don't have /dev/stdin")
484485
def test_devstdin_input(self):
485486

486487
async def devstdin_input(message):

Lib/test/test_c_locale_coercion.py

+10-11
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,16 @@
2626
TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"]
2727

2828
# Apply some platform dependent overrides
29-
if sys.platform.startswith("linux"):
30-
if support.is_android:
31-
# Android defaults to using UTF-8 for all system interfaces
32-
EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
33-
EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
34-
else:
35-
# Linux distros typically alias the POSIX locale directly to the C
36-
# locale.
37-
# TODO: Once https://bugs.python.org/issue30672 is addressed, we'll be
38-
# able to check this case unconditionally
39-
EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX")
29+
if sys.platform == "android":
30+
# Android defaults to using UTF-8 for all system interfaces
31+
EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
32+
EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
33+
elif sys.platform.startswith("linux"):
34+
# Linux distros typically alias the POSIX locale directly to the C
35+
# locale.
36+
# TODO: Once https://bugs.python.org/issue30672 is addressed, we'll be
37+
# able to check this case unconditionally
38+
EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX")
4039
elif sys.platform.startswith("aix"):
4140
# AIX uses iso8859-1 in the C locale, other *nix platforms use ASCII
4241
EXPECTED_C_LOCALE_STREAM_ENCODING = "iso8859-1"

Lib/test/test_fcntl.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ def test_fcntl_bad_file_overflow(self):
129129
fcntl.fcntl(BadFile(INT_MIN - 1), fcntl.F_SETFL, os.O_NONBLOCK)
130130

131131
@unittest.skipIf(
132-
any(platform.machine().startswith(name) for name in {"arm", "aarch"})
133-
and platform.system() in {"Linux", "Android"},
132+
platform.machine().startswith(("arm", "aarch"))
133+
and platform.system() in ("Linux", "Android"),
134134
"ARM Linux returns EINVAL for F_NOTIFY DN_MULTISHOT")
135135
def test_fcntl_64_bit(self):
136136
# Issue #1309352: fcntl shouldn't fail when the third arg fits in a

Lib/test/test_logging.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ def test_name(self):
603603
def test_builtin_handlers(self):
604604
# We can't actually *use* too many handlers in the tests,
605605
# but we can try instantiating them with various options
606-
if sys.platform in ('linux', 'darwin'):
606+
if sys.platform in ('linux', 'android', 'darwin'):
607607
for existing in (True, False):
608608
fn = make_temp_file()
609609
if not existing:
@@ -667,7 +667,7 @@ def test_path_objects(self):
667667
(logging.handlers.RotatingFileHandler, (pfn, 'a')),
668668
(logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
669669
)
670-
if sys.platform in ('linux', 'darwin'):
670+
if sys.platform in ('linux', 'android', 'darwin'):
671671
cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
672672
for cls, args in cases:
673673
h = cls(*args, encoding="utf-8")

Lib/test/test_mmap.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ def test_flush_return_value(self):
837837
mm.write(b'python')
838838
result = mm.flush()
839839
self.assertIsNone(result)
840-
if sys.platform.startswith('linux'):
840+
if sys.platform.startswith(('linux', 'android')):
841841
# 'offset' must be a multiple of mmap.PAGESIZE on Linux.
842842
# See bpo-34754 for details.
843843
self.assertRaises(OSError, mm.flush, 1, len(b'python'))

Lib/test/test_os.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -3533,9 +3533,8 @@ def test_set_get_priority(self):
35333533
class TestSendfile(unittest.IsolatedAsyncioTestCase):
35343534

35353535
DATA = b"12345abcde" * 16 * 1024 # 160 KiB
3536-
SUPPORT_HEADERS_TRAILERS = not sys.platform.startswith("linux") and \
3537-
not sys.platform.startswith("solaris") and \
3538-
not sys.platform.startswith("sunos")
3536+
SUPPORT_HEADERS_TRAILERS = (
3537+
not sys.platform.startswith(("linux", "android", "solaris", "sunos")))
35393538
requires_headers_trailers = unittest.skipUnless(SUPPORT_HEADERS_TRAILERS,
35403539
'requires headers and trailers support')
35413540
requires_32b = unittest.skipUnless(sys.maxsize < 2**32,
@@ -5256,7 +5255,7 @@ def test_fork(self):
52565255
else:
52575256
assert_python_ok("-c", code, PYTHONMALLOC="malloc_debug")
52585257

5259-
@unittest.skipUnless(sys.platform in ("linux", "darwin"),
5258+
@unittest.skipUnless(sys.platform in ("linux", "android", "darwin"),
52605259
"Only Linux and macOS detect this today.")
52615260
def test_fork_warns_when_non_python_thread_exists(self):
52625261
code = """if 1:

Lib/test/test_resource.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def test_pagesize(self):
138138
self.assertIsInstance(pagesize, int)
139139
self.assertGreaterEqual(pagesize, 0)
140140

141-
@unittest.skipUnless(sys.platform == 'linux', 'test requires Linux')
141+
@unittest.skipUnless(sys.platform in ('linux', 'android'), 'Linux only')
142142
def test_linux_constants(self):
143143
for attr in ['MSGQUEUE', 'NICE', 'RTPRIO', 'RTTIME', 'SIGPENDING']:
144144
with contextlib.suppress(AttributeError):

Lib/test/test_socket.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -1199,8 +1199,8 @@ def testGetServBy(self):
11991199
# I've ordered this by protocols that have both a tcp and udp
12001200
# protocol, at least for modern Linuxes.
12011201
if (
1202-
sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd'))
1203-
or sys.platform == 'linux'
1202+
sys.platform.startswith(
1203+
('linux', 'android', 'freebsd', 'netbsd', 'gnukfreebsd'))
12041204
or is_apple
12051205
):
12061206
# avoid the 'echo' service on this platform, as there is an
@@ -1218,8 +1218,7 @@ def testGetServBy(self):
12181218
raise OSError
12191219
# Try same call with optional protocol omitted
12201220
# Issue #26936: Android getservbyname() was broken before API 23.
1221-
if (not hasattr(sys, 'getandroidapilevel') or
1222-
sys.getandroidapilevel() >= 23):
1221+
if (not support.is_android) or sys.getandroidapilevel() >= 23:
12231222
port2 = socket.getservbyname(service)
12241223
eq(port, port2)
12251224
# Try udp, but don't barf if it doesn't exist
@@ -1577,8 +1576,7 @@ def testGetaddrinfo(self):
15771576
# port can be a string service name such as "http", a numeric
15781577
# port number or None
15791578
# Issue #26936: Android getaddrinfo() was broken before API level 23.
1580-
if (not hasattr(sys, 'getandroidapilevel') or
1581-
sys.getandroidapilevel() >= 23):
1579+
if (not support.is_android) or sys.getandroidapilevel() >= 23:
15821580
socket.getaddrinfo(HOST, "http")
15831581
socket.getaddrinfo(HOST, 80)
15841582
socket.getaddrinfo(HOST, None)
@@ -3196,7 +3194,7 @@ def _testSendmsgTimeout(self):
31963194
# Linux supports MSG_DONTWAIT when sending, but in general, it
31973195
# only works when receiving. Could add other platforms if they
31983196
# support it too.
3199-
@skipWithClientIf(sys.platform not in {"linux"},
3197+
@skipWithClientIf(sys.platform not in {"linux", "android"},
32003198
"MSG_DONTWAIT not known to work on this platform when "
32013199
"sending")
32023200
def testSendmsgDontWait(self):
@@ -5634,7 +5632,7 @@ def test_setblocking_invalidfd(self):
56345632
sock.setblocking(False)
56355633

56365634

5637-
@unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
5635+
@unittest.skipUnless(sys.platform in ('linux', 'android'), 'Linux specific test')
56385636
class TestLinuxAbstractNamespace(unittest.TestCase):
56395637

56405638
UNIX_PATH_MAX = 108
@@ -5759,7 +5757,8 @@ def testUnencodableAddr(self):
57595757
self.addCleanup(os_helper.unlink, path)
57605758
self.assertEqual(self.sock.getsockname(), path)
57615759

5762-
@unittest.skipIf(sys.platform == 'linux', 'Linux specific test')
5760+
@unittest.skipIf(sys.platform in ('linux', 'android'),
5761+
'Linux behavior is tested by TestLinuxAbstractNamespace')
57635762
def testEmptyAddress(self):
57645763
# Test that binding empty address fails.
57655764
self.assertRaises(OSError, self.sock.bind, "")

Lib/test/test_ssl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4914,7 +4914,7 @@ def run(self):
49144914
pass # closed, protocol error, etc.
49154915

49164916
def non_linux_skip_if_other_okay_error(self, err):
4917-
if sys.platform == "linux":
4917+
if sys.platform in ("linux", "android"):
49184918
return # Expect the full test setup to always work on Linux.
49194919
if (isinstance(err, ConnectionResetError) or
49204920
(isinstance(err, OSError) and err.errno == errno.EINVAL) or

Lib/test/test_sys.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ def test_thread_info(self):
668668
self.assertEqual(len(info), 3)
669669
self.assertIn(info.name, ('nt', 'pthread', 'pthread-stubs', 'solaris', None))
670670
self.assertIn(info.lock, ('semaphore', 'mutex+cond', None))
671-
if sys.platform.startswith(("linux", "freebsd")):
671+
if sys.platform.startswith(("linux", "android", "freebsd")):
672672
self.assertEqual(info.name, "pthread")
673673
elif sys.platform == "win32":
674674
self.assertEqual(info.name, "nt")
@@ -1101,8 +1101,7 @@ def __del__(self):
11011101
self.assertEqual(stdout.rstrip(), b"")
11021102
self.assertEqual(stderr.rstrip(), b"")
11031103

1104-
@unittest.skipUnless(hasattr(sys, 'getandroidapilevel'),
1105-
'need sys.getandroidapilevel()')
1104+
@unittest.skipUnless(sys.platform == "android", "Android only")
11061105
def test_getandroidapilevel(self):
11071106
level = sys.getandroidapilevel()
11081107
self.assertIsInstance(level, int)

Lib/test/test_sysconfig.py

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import platform
2+
import re
13
import unittest
24
import sys
35
import os
@@ -516,12 +518,9 @@ def test_EXT_SUFFIX_in_vars(self):
516518
vars = sysconfig.get_config_vars()
517519
self.assertEqual(vars['EXT_SUFFIX'], _imp.extension_suffixes()[0])
518520

519-
@unittest.skipUnless(sys.platform == 'linux' and
520-
hasattr(sys.implementation, '_multiarch'),
521-
'multiarch-specific test')
522-
def test_triplet_in_ext_suffix(self):
521+
@unittest.skipUnless(sys.platform == 'linux', 'Linux-specific test')
522+
def test_linux_ext_suffix(self):
523523
ctypes = import_module('ctypes')
524-
import platform, re
525524
machine = platform.machine()
526525
suffix = sysconfig.get_config_var('EXT_SUFFIX')
527526
if re.match('(aarch64|arm|mips|ppc|powerpc|s390|sparc)', machine):
@@ -534,6 +533,19 @@ def test_triplet_in_ext_suffix(self):
534533
self.assertTrue(suffix.endswith(expected_suffixes),
535534
f'unexpected suffix {suffix!r}')
536535

536+
@unittest.skipUnless(sys.platform == 'android', 'Android-specific test')
537+
def test_android_ext_suffix(self):
538+
machine = platform.machine()
539+
suffix = sysconfig.get_config_var('EXT_SUFFIX')
540+
expected_triplet = {
541+
"x86_64": "x86_64-linux-android",
542+
"i686": "i686-linux-android",
543+
"aarch64": "aarch64-linux-android",
544+
"armv7l": "arm-linux-androideabi",
545+
}[machine]
546+
self.assertTrue(suffix.endswith(f"-{expected_triplet}.so"),
547+
f"{machine=}, {suffix=}")
548+
537549
@unittest.skipUnless(sys.platform == 'darwin', 'OS X-specific test')
538550
def test_osx_ext_suffix(self):
539551
suffix = sysconfig.get_config_var('EXT_SUFFIX')

Lib/test/test_tarfile.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ def _fs_supports_holes():
11861186
#
11871187
# The function returns False if page size is larger than 4 KiB.
11881188
# For example, ppc64 uses pages of 64 KiB.
1189-
if sys.platform.startswith("linux"):
1189+
if sys.platform.startswith(("linux", "android")):
11901190
# Linux evidentially has 512 byte st_blocks units.
11911191
name = os.path.join(TEMPDIR, "sparse-test")
11921192
with open(name, "wb") as fobj:

Lib/test/test_time.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ def test_process_time(self):
511511

512512
def test_thread_time(self):
513513
if not hasattr(time, 'thread_time'):
514-
if sys.platform.startswith(('linux', 'win')):
514+
if sys.platform.startswith(('linux', 'android', 'win')):
515515
self.fail("time.thread_time() should be available on %r"
516516
% (sys.platform,))
517517
else:

Lib/uuid.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
import platform
6363
_platform_system = platform.system()
6464
_AIX = _platform_system == 'AIX'
65-
_LINUX = _platform_system == 'Linux'
65+
_LINUX = _platform_system in ('Linux', 'Android')
6666

6767
_MAC_DELIM = b':'
6868
_MAC_OMITS_LEADING_ZEROES = False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Change Android's :data:`sys.platform` from ``"linux"`` to ``"android"``.

0 commit comments

Comments
 (0)