Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-71052: Change Android's sys.platform from "linux" to "android" #116215

Merged
merged 3 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 20 additions & 25 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1367,47 +1367,42 @@ always available.

.. data:: platform

This string contains a platform identifier that can be used to append
platform-specific components to :data:`sys.path`, for instance.

For Unix systems, except on Linux and AIX, this is the lowercased OS name as
returned by ``uname -s`` with the first part of the version as returned by
``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, *at the time
when Python was built*. Unless you want to test for a specific system
version, it is therefore recommended to use the following idiom::

if sys.platform.startswith('freebsd'):
# FreeBSD-specific code here...
elif sys.platform.startswith('linux'):
# Linux-specific code here...
elif sys.platform.startswith('aix'):
# AIX-specific code here...

For other systems, the values are:
A string containing a platform identifier. Known values are:

================ ===========================
System ``platform`` value
================ ===========================
AIX ``'aix'``
Android ``'android'``
Emscripten ``'emscripten'``
iOS ``'ios'``
Linux ``'linux'``
WASI ``'wasi'``
macOS ``'darwin'``
Windows ``'win32'``
Windows/Cygwin ``'cygwin'``
macOS ``'darwin'``
WASI ``'wasi'``
================ ===========================

On Unix systems not listed in the table, the value is the lowercased OS name
as returned by ``uname -s``, with the first part of the version as returned by
``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, *at the time
when Python was built*. Unless you want to test for a specific system
version, it is therefore recommended to use the following idiom::

if sys.platform.startswith('freebsd'):
# FreeBSD-specific code here...

.. versionchanged:: 3.3
On Linux, :data:`sys.platform` doesn't contain the major version anymore.
It is always ``'linux'``, instead of ``'linux2'`` or ``'linux3'``. Since
older Python versions include the version number, it is recommended to
always use the ``startswith`` idiom presented above.
It is always ``'linux'``, instead of ``'linux2'`` or ``'linux3'``.

.. versionchanged:: 3.8
On AIX, :data:`sys.platform` doesn't contain the major version anymore.
It is always ``'aix'``, instead of ``'aix5'`` or ``'aix7'``. Since
older Python versions include the version number, it is recommended to
always use the ``startswith`` idiom presented above.
It is always ``'aix'``, instead of ``'aix5'`` or ``'aix7'``.

.. versionchanged:: 3.13
On Android, :data:`sys.platform` now returns ``'android'`` rather than
``'linux'``.

.. seealso::

Expand Down
2 changes: 1 addition & 1 deletion Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ def LoadLibrary(self, name):

if _os.name == "nt":
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
elif hasattr(_sys, "getandroidapilevel"):
elif _sys.platform == "android":
pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2])
elif _sys.platform == "cygwin":
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
Expand Down
6 changes: 1 addition & 5 deletions Lib/multiprocessing/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,7 @@ def log_to_stderr(level=None):
# Abstract socket support

def _platform_supports_abstract_sockets():
if sys.platform == "linux":
return True
if hasattr(sys, 'getandroidapilevel'):
return True
return False
return sys.platform in ("linux", "android")


def is_abstract_socket_namespace(address):
Expand Down
3 changes: 2 additions & 1 deletion Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024
# This should never be removed, see rationale in:
# https://bugs.python.org/issue43743#msg393429
_USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux")
_USE_CP_SENDFILE = (hasattr(os, "sendfile")
and sys.platform.startswith(("linux", "android")))
_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS

# CMD defaults in Windows 10
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ def requires_debug_ranges(reason='requires co_positions / debug_ranges'):
# Is not actually used in tests, but is kept for compatibility.
is_jython = sys.platform.startswith('java')

is_android = hasattr(sys, 'getandroidapilevel')
is_android = sys.platform == "android"

if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/os_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ def __fspath__(self):
def fd_count():
"""Count the number of open file descriptors.
"""
if sys.platform.startswith(('linux', 'freebsd', 'emscripten')):
if sys.platform.startswith(('linux', 'android', 'freebsd', 'emscripten')):
fd_path = "/proc/self/fd"
elif sys.platform == "darwin":
fd_path = "/dev/fd"
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_asyncio/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,8 @@ async def empty_error():
self.assertEqual(output, None)
self.assertEqual(exitcode, 0)

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

async def devstdin_input(message):
Expand Down
21 changes: 10 additions & 11 deletions Lib/test/test_c_locale_coercion.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,16 @@
TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"]

# Apply some platform dependent overrides
if sys.platform.startswith("linux"):
if support.is_android:
# Android defaults to using UTF-8 for all system interfaces
EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
else:
# Linux distros typically alias the POSIX locale directly to the C
# locale.
# TODO: Once https://bugs.python.org/issue30672 is addressed, we'll be
# able to check this case unconditionally
EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX")
if sys.platform == "android":
# Android defaults to using UTF-8 for all system interfaces
EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
elif sys.platform.startswith("linux"):
# Linux distros typically alias the POSIX locale directly to the C
# locale.
# TODO: Once https://bugs.python.org/issue30672 is addressed, we'll be
# able to check this case unconditionally
EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX")
elif sys.platform.startswith("aix"):
# AIX uses iso8859-1 in the C locale, other *nix platforms use ASCII
EXPECTED_C_LOCALE_STREAM_ENCODING = "iso8859-1"
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_fcntl.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ def test_fcntl_bad_file_overflow(self):
fcntl.fcntl(BadFile(INT_MIN - 1), fcntl.F_SETFL, os.O_NONBLOCK)

@unittest.skipIf(
any(platform.machine().startswith(name) for name in {"arm", "aarch"})
and platform.system() in {"Linux", "Android"},
platform.machine().startswith(("arm", "aarch"))
and platform.system() in ("Linux", "Android"),
"ARM Linux returns EINVAL for F_NOTIFY DN_MULTISHOT")
def test_fcntl_64_bit(self):
# Issue #1309352: fcntl shouldn't fail when the third arg fits in a
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ def test_name(self):
def test_builtin_handlers(self):
# We can't actually *use* too many handlers in the tests,
# but we can try instantiating them with various options
if sys.platform in ('linux', 'darwin'):
if sys.platform in ('linux', 'android', 'darwin'):
for existing in (True, False):
fn = make_temp_file()
if not existing:
Expand Down Expand Up @@ -667,7 +667,7 @@ def test_path_objects(self):
(logging.handlers.RotatingFileHandler, (pfn, 'a')),
(logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
)
if sys.platform in ('linux', 'darwin'):
if sys.platform in ('linux', 'android', 'darwin'):
cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
for cls, args in cases:
h = cls(*args, encoding="utf-8")
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_mmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ def test_flush_return_value(self):
mm.write(b'python')
result = mm.flush()
self.assertIsNone(result)
if sys.platform.startswith('linux'):
if sys.platform.startswith(('linux', 'android')):
# 'offset' must be a multiple of mmap.PAGESIZE on Linux.
# See bpo-34754 for details.
self.assertRaises(OSError, mm.flush, 1, len(b'python'))
Expand Down
7 changes: 3 additions & 4 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -3533,9 +3533,8 @@ def test_set_get_priority(self):
class TestSendfile(unittest.IsolatedAsyncioTestCase):

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

@unittest.skipUnless(sys.platform in ("linux", "darwin"),
@unittest.skipUnless(sys.platform in ("linux", "android", "darwin"),
"Only Linux and macOS detect this today.")
def test_fork_warns_when_non_python_thread_exists(self):
code = """if 1:
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def test_pagesize(self):
self.assertIsInstance(pagesize, int)
self.assertGreaterEqual(pagesize, 0)

@unittest.skipUnless(sys.platform == 'linux', 'test requires Linux')
@unittest.skipUnless(sys.platform in ('linux', 'android'), 'Linux only')
def test_linux_constants(self):
for attr in ['MSGQUEUE', 'NICE', 'RTPRIO', 'RTTIME', 'SIGPENDING']:
with contextlib.suppress(AttributeError):
Expand Down
17 changes: 8 additions & 9 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1199,8 +1199,8 @@ def testGetServBy(self):
# I've ordered this by protocols that have both a tcp and udp
# protocol, at least for modern Linuxes.
if (
sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd'))
or sys.platform == 'linux'
sys.platform.startswith(
('linux', 'android', 'freebsd', 'netbsd', 'gnukfreebsd'))
or is_apple
):
# avoid the 'echo' service on this platform, as there is an
Expand All @@ -1218,8 +1218,7 @@ def testGetServBy(self):
raise OSError
# Try same call with optional protocol omitted
# Issue #26936: Android getservbyname() was broken before API 23.
if (not hasattr(sys, 'getandroidapilevel') or
sys.getandroidapilevel() >= 23):
if (not support.is_android) or sys.getandroidapilevel() >= 23:
port2 = socket.getservbyname(service)
eq(port, port2)
# Try udp, but don't barf if it doesn't exist
Expand Down Expand Up @@ -1577,8 +1576,7 @@ def testGetaddrinfo(self):
# port can be a string service name such as "http", a numeric
# port number or None
# Issue #26936: Android getaddrinfo() was broken before API level 23.
if (not hasattr(sys, 'getandroidapilevel') or
sys.getandroidapilevel() >= 23):
if (not support.is_android) or sys.getandroidapilevel() >= 23:
socket.getaddrinfo(HOST, "http")
socket.getaddrinfo(HOST, 80)
socket.getaddrinfo(HOST, None)
Expand Down Expand Up @@ -3196,7 +3194,7 @@ def _testSendmsgTimeout(self):
# Linux supports MSG_DONTWAIT when sending, but in general, it
# only works when receiving. Could add other platforms if they
# support it too.
@skipWithClientIf(sys.platform not in {"linux"},
@skipWithClientIf(sys.platform not in {"linux", "android"},
"MSG_DONTWAIT not known to work on this platform when "
"sending")
def testSendmsgDontWait(self):
Expand Down Expand Up @@ -5634,7 +5632,7 @@ def test_setblocking_invalidfd(self):
sock.setblocking(False)


@unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
@unittest.skipUnless(sys.platform in ('linux', 'android'), 'Linux specific test')
class TestLinuxAbstractNamespace(unittest.TestCase):

UNIX_PATH_MAX = 108
Expand Down Expand Up @@ -5759,7 +5757,8 @@ def testUnencodableAddr(self):
self.addCleanup(os_helper.unlink, path)
self.assertEqual(self.sock.getsockname(), path)

@unittest.skipIf(sys.platform == 'linux', 'Linux specific test')
@unittest.skipIf(sys.platform in ('linux', 'android'),
'Linux behavior is tested by TestLinuxAbstractNamespace')
def testEmptyAddress(self):
# Test that binding empty address fails.
self.assertRaises(OSError, self.sock.bind, "")
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4871,7 +4871,7 @@ def run(self):
pass # closed, protocol error, etc.

def non_linux_skip_if_other_okay_error(self, err):
if sys.platform == "linux":
if sys.platform in ("linux", "android"):
return # Expect the full test setup to always work on Linux.
if (isinstance(err, ConnectionResetError) or
(isinstance(err, OSError) and err.errno == errno.EINVAL) or
Expand Down
5 changes: 2 additions & 3 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ def test_thread_info(self):
self.assertEqual(len(info), 3)
self.assertIn(info.name, ('nt', 'pthread', 'pthread-stubs', 'solaris', None))
self.assertIn(info.lock, ('semaphore', 'mutex+cond', None))
if sys.platform.startswith(("linux", "freebsd")):
if sys.platform.startswith(("linux", "android", "freebsd")):
self.assertEqual(info.name, "pthread")
elif sys.platform == "win32":
self.assertEqual(info.name, "nt")
Expand Down Expand Up @@ -1101,8 +1101,7 @@ def __del__(self):
self.assertEqual(stdout.rstrip(), b"")
self.assertEqual(stderr.rstrip(), b"")

@unittest.skipUnless(hasattr(sys, 'getandroidapilevel'),
'need sys.getandroidapilevel()')
@unittest.skipUnless(sys.platform == "android", "Android only")
def test_getandroidapilevel(self):
level = sys.getandroidapilevel()
self.assertIsInstance(level, int)
Expand Down
22 changes: 17 additions & 5 deletions Lib/test/test_sysconfig.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import platform
import re
import unittest
import sys
import os
Expand Down Expand Up @@ -516,12 +518,9 @@ def test_EXT_SUFFIX_in_vars(self):
vars = sysconfig.get_config_vars()
self.assertEqual(vars['EXT_SUFFIX'], _imp.extension_suffixes()[0])

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

@unittest.skipUnless(sys.platform == 'android', 'Android-specific test')
def test_android_ext_suffix(self):
machine = platform.machine()
suffix = sysconfig.get_config_var('EXT_SUFFIX')
expected_triplet = {
"x86_64": "x86_64-linux-android",
"i686": "i686-linux-android",
"aarch64": "aarch64-linux-android",
"armv7l": "arm-linux-androideabi",
}[machine]
self.assertTrue(suffix.endswith(f"-{expected_triplet}.so"),
f"{machine=}, {suffix=}")

@unittest.skipUnless(sys.platform == 'darwin', 'OS X-specific test')
def test_osx_ext_suffix(self):
suffix = sysconfig.get_config_var('EXT_SUFFIX')
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1186,7 +1186,7 @@ def _fs_supports_holes():
#
# The function returns False if page size is larger than 4 KiB.
# For example, ppc64 uses pages of 64 KiB.
if sys.platform.startswith("linux"):
if sys.platform.startswith(("linux", "android")):
# Linux evidentially has 512 byte st_blocks units.
name = os.path.join(TEMPDIR, "sparse-test")
with open(name, "wb") as fobj:
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def test_process_time(self):

def test_thread_time(self):
if not hasattr(time, 'thread_time'):
if sys.platform.startswith(('linux', 'win')):
if sys.platform.startswith(('linux', 'android', 'win')):
self.fail("time.thread_time() should be available on %r"
% (sys.platform,))
else:
Expand Down
2 changes: 1 addition & 1 deletion Lib/uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
import platform
_platform_system = platform.system()
_AIX = _platform_system == 'AIX'
_LINUX = _platform_system == 'Linux'
_LINUX = _platform_system in ('Linux', 'Android')

_MAC_DELIM = b':'
_MAC_OMITS_LEADING_ZEROES = False
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change Android's :data:`sys.platform` from ``"linux"`` to ``"android"``.
Loading
Loading