Skip to content
Closed
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
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ Lib/test/data/*
/Makefile
/Makefile.pre
/iOSTestbed.*
/tvOSTestbed.*
/visionOSTestbed.*
iOS/Frameworks/
iOS/Resources/Info.plist
iOS/testbed/build
Expand All @@ -81,6 +83,27 @@ iOS/testbed/Python.xcframework/ios-*/Python.framework
iOS/testbed/iOSTestbed.xcodeproj/project.xcworkspace
iOS/testbed/iOSTestbed.xcodeproj/xcuserdata
iOS/testbed/iOSTestbed.xcodeproj/xcshareddata
tvOS/testbed/build
tvOS/testbed/Python.xcframework/tvos-*/bin
tvOS/testbed/Python.xcframework/tvos-*/include
tvOS/testbed/Python.xcframework/tvos-*/lib
tvOS/testbed/Python.xcframework/tvos-*/Python.framework
tvOS/testbed/tvOSTestbed.xcodeproj/project.xcworkspace
tvOS/testbed/tvOSTestbed.xcodeproj/xcuserdata
tvOS/testbed/tvOSTestbed.xcodeproj/xcshareddata
visionOS/testbed/Python.xcframework/xros-*/bin
visionOS/testbed/Python.xcframework/xros-*/include
visionOS/testbed/Python.xcframework/xros-*/lib
visionOS/testbed/Python.xcframework/xros-*/Python.framework
visionOS/testbed/visionOSTestbed.xcodeproj/project.xcworkspace
visionOS/testbed/visionOSTestbed.xcodeproj/xcuserdata
visionOS/testbed/visionOSTestbed.xcodeproj/xcshareddata
tvOS/Frameworks
tvOS/Resources/Info.plist
watchOS/Frameworks
watchOS/Resources/Info.plist
visionOS/Frameworks
visionOS/Resources/Info.plist
Mac/Makefile
Mac/PythonLauncher/Info.plist
Mac/PythonLauncher/Makefile
Expand Down
2 changes: 1 addition & 1 deletion Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ def __init__(self, name, mode=DEFAULT_MODE, handle=None,
if name:
name = _os.fspath(name)

# If the filename that has been provided is an iOS/tvOS/watchOS
# If the filename that has been provided is an iOS/tvOS/watchOS/visionOS
# .fwork file, dereference the location to the true origin of the
# binary.
if name.endswith(".fwork"):
Expand Down
4 changes: 2 additions & 2 deletions Lib/ctypes/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def dllist():
if (name := _get_module_filename(h)) is not None]
return libraries

elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}:
elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos", "visionos"}:
from ctypes.macholib.dyld import dyld_find as _dyld_find
def find_library(name):
possible = ['lib%s.dylib' % name,
Expand Down Expand Up @@ -425,7 +425,7 @@ def find_library(name):
# https://man.openbsd.org/dl_iterate_phdr
# https://docs.oracle.com/cd/E88353_01/html/E37843/dl-iterate-phdr-3c.html
if (os.name == "posix" and
sys.platform not in {"darwin", "ios", "tvos", "watchos"}):
sys.platform not in {"darwin", "ios", "tvos", "watchos", "visionos"}):
import ctypes
if hasattr((_libc := ctypes.CDLL(None)), "dl_iterate_phdr"):

Expand Down
4 changes: 2 additions & 2 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

# Bootstrap-related code ######################################################
_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos', 'visionos'
_CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
+ _CASE_INSENSITIVE_PLATFORMS_STR_KEY)

Expand Down Expand Up @@ -1535,7 +1535,7 @@ def _get_supported_file_loaders():
"""
extension_loaders = []
if hasattr(_imp, 'create_dynamic'):
if sys.platform in {"ios", "tvos", "watchos"}:
if sys.platform in {"ios", "tvos", "watchos", "visionos"}:
extension_loaders = [(AppleFrameworkLoader, [
suffix.replace(".so", ".fwork")
for suffix in _imp.extension_suffixes()
Expand Down
110 changes: 105 additions & 5 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,78 @@ def ios_ver(system="", release="", model="", is_simulator=False):
return IOSVersionInfo(system, release, model, is_simulator)


# A namedtuple for tvOS version information.
TVOSVersionInfo = collections.namedtuple(
"TVOSVersionInfo",
["system", "release", "model", "is_simulator"]
)


def tvos_ver(system="", release="", model="", is_simulator=False):
"""Get tvOS version information, and return it as a namedtuple:
(system, release, model, is_simulator).

If values can't be determined, they are set to values provided as
parameters.
"""
if sys.platform == "tvos":
# TODO: Can the iOS implementation be used here?
import _ios_support
result = _ios_support.get_platform_ios()
if result is not None:
return TVOSVersionInfo(*result)

return TVOSVersionInfo(system, release, model, is_simulator)


# A namedtuple for watchOS version information.
WatchOSVersionInfo = collections.namedtuple(
"WatchOSVersionInfo",
["system", "release", "model", "is_simulator"]
)


def watchos_ver(system="", release="", model="", is_simulator=False):
"""Get watchOS version information, and return it as a namedtuple:
(system, release, model, is_simulator).

If values can't be determined, they are set to values provided as
parameters.
"""
if sys.platform == "watchos":
# TODO: Can the iOS implementation be used here?
import _ios_support
result = _ios_support.get_platform_ios()
if result is not None:
return WatchOSVersionInfo(*result)

return WatchOSVersionInfo(system, release, model, is_simulator)


# A namedtuple for visionOS version information.
VisionOSVersionInfo = collections.namedtuple(
"VisionOSVersionInfo",
["system", "release", "model", "is_simulator"]
)


def visionos_ver(system="", release="", model="", is_simulator=False):
"""Get visionOS version information, and return it as a namedtuple:
(system, release, model, is_simulator).

If values can't be determined, they are set to values provided as
parameters.
"""
if sys.platform == "visionos":
# TODO: Can the iOS implementation be used here?
import _ios_support
result = _ios_support.get_platform_ios()
if result is not None:
return VisionOSVersionInfo(*result)

return VisionOSVersionInfo(system, release, model, is_simulator)


def _java_getprop(name, default):
"""This private helper is deprecated in 3.13 and will be removed in 3.15"""
from java.lang import System
Expand Down Expand Up @@ -727,7 +799,7 @@ def _syscmd_file(target, default=''):
default in case the command should fail.

"""
if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'}:
if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'watchos', 'visionos'}:
# XXX Others too ?
return default

Expand Down Expand Up @@ -891,14 +963,30 @@ def get_OpenVMS():
csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
return 'Alpha' if cpu_number >= 128 else 'VAX'

# On the iOS simulator, os.uname returns the architecture as uname.machine.
# On device it returns the model name for some reason; but there's only one
# CPU architecture for iOS devices, so we know the right answer.
# On the iOS/tvOS/watchOS/visionOS simulator, os.uname returns the architecture as
# uname.machine. On device it returns the model name for some reason; but
# there's only one CPU architecture for devices, so we know the right
# answer.
def get_ios():
if sys.implementation._multiarch.endswith("simulator"):
return os.uname().machine
return 'arm64'

def get_tvos():
if sys.implementation._multiarch.endswith("simulator"):
return os.uname().machine
return 'arm64'

def get_watchos():
if sys.implementation._multiarch.endswith("simulator"):
return os.uname().machine
return 'arm64_32'

def get_visionos():
if sys.implementation._multiarch.endswith("simulator"):
return os.uname().machine
return 'arm64'

def from_subprocess():
"""
Fall back to `uname -p`
Expand Down Expand Up @@ -1058,9 +1146,15 @@ def uname():
system = 'Android'
release = android_ver().release

# Normalize responses on iOS
# Normalize responses on Apple mobile platforms
if sys.platform == 'ios':
system, release, _, _ = ios_ver()
if sys.platform == 'tvos':
system, release, _, _ = tvos_ver()
if sys.platform == 'watchos':
system, release, _, _ = watchos_ver()
if sys.platform == 'visionos':
system, release, _, _ = visionos_ver()

vals = system, node, release, version, machine
# Replace 'unknown' values with the more portable ''
Expand Down Expand Up @@ -1350,6 +1444,12 @@ def platform(aliased=False, terse=False):
# macOS and iOS both report as a "Darwin" kernel
if sys.platform == "ios":
system, release, _, _ = ios_ver()
elif sys.platform == "tvos":
system, release, _, _ = tvos_ver()
elif sys.platform == "watchos":
system, release, _, _ = watchos_ver()
elif sys.platform == "visionos":
system, release, _, _ = visionos_ver()
else:
macos_release = mac_ver()[0]
if macos_release:
Expand Down
4 changes: 2 additions & 2 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ def _getuserbase():
if env_base:
return env_base

# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
# Emscripten, iOS, tvOS, visionOS, VxWorks, WASI, and watchOS have no home directories
if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "visionos", "wasi", "watchos"}:
return None

def joinuser(*args):
Expand Down
2 changes: 1 addition & 1 deletion Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
_mswindows = True

# some platforms do not support subprocesses
_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"}
_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos", "visionos"}

if _mswindows:
import _winapi
Expand Down
17 changes: 16 additions & 1 deletion Lib/sysconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
_ALWAYS_STR = {
'IPHONEOS_DEPLOYMENT_TARGET',
'MACOSX_DEPLOYMENT_TARGET',
'TVOS_DEPLOYMENT_TARGET',
'WATCHOS_DEPLOYMENT_TARGET',
'XROS_DEPLOYMENT_TARGET',
}

_INSTALL_SCHEMES = {
Expand Down Expand Up @@ -119,7 +122,7 @@ def _getuserbase():
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories.
# Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling.
system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0]
if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
if system_name in {"emscripten", "ios", "tvos", "visionos", "vxworks", "wasi", "watchos"}:
return None

def joinuser(*args):
Expand Down Expand Up @@ -730,6 +733,18 @@ def get_platform():
release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0")
osname = sys.platform
machine = sys.implementation._multiarch
elif sys.platform == "tvos":
release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0")
osname = sys.platform
machine = sys.implementation._multiarch
elif sys.platform == "watchos":
release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0")
osname = sys.platform
machine = sys.implementation._multiarch
elif sys.platform == "visionos":
release = get_config_vars().get("XROS_DEPLOYMENT_TARGET", "2.0")
osname = sys.platform
machine = sys.implementation._multiarch
else:
import _osx_support
osname, release, machine = _osx_support.get_platform_osx(
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/datetimetester.py
Original file line number Diff line number Diff line change
Expand Up @@ -7159,9 +7159,9 @@ def test_datetime_from_timestamp(self):
self.assertEqual(dt_orig, dt_rt)

def test_type_check_in_subinterp(self):
# iOS requires the use of the custom framework loader,
# Apple mobile platforms require the use of the custom framework loader,
# not the ExtensionFileLoader.
if sys.platform == "ios":
if support.is_apple_mobile:
extension_loader = "AppleFrameworkLoader"
else:
extension_loader = "ExtensionFileLoader"
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ def skip_android_selinux(name):
sys.platform == "android", f"Android blocks {name} with SELinux"
)

if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos", "visionos"}:
unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
else:
unix_shell = None
Expand All @@ -574,7 +574,7 @@ def skip_emscripten_stack_overflow():
def skip_wasi_stack_overflow():
return unittest.skipIf(is_wasi, "Exhausts stack on WASI")

is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"}
is_apple_mobile = sys.platform in {"ios", "tvos", "watchos", "visionos"}
is_apple = is_apple_mobile or sys.platform == "darwin"

has_fork_support = hasattr(os, "fork") and not (
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_ctypes/test_dllist.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


WINDOWS = os.name == "nt"
APPLE = sys.platform in {"darwin", "ios", "tvos", "watchos"}
APPLE = sys.platform in {"darwin", "ios", "tvos", "watchos", "visionos"}

if WINDOWS:
KNOWN_LIBRARIES = ["KERNEL32.DLL"]
Expand Down
14 changes: 11 additions & 3 deletions Lib/test/test_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,21 @@ def test_uname(self):
if sys.platform == "android":
self.assertEqual(res.system, "Android")
self.assertEqual(res.release, platform.android_ver().release)
elif sys.platform == "ios":
elif support.is_apple_mobile:
# Platform module needs ctypes for full operation. If ctypes
# isn't available, there's no ObjC module, and dummy values are
# returned.
if _ctypes:
self.assertIn(res.system, {"iOS", "iPadOS"})
self.assertEqual(res.release, platform.ios_ver().release)
if sys.platform == "ios":
# iPads also identify as iOS
self.assertIn(res.system, {"iOS", "iPadOS"})
else:
# All other platforms - sys.platform is the lower case
# form of system (e.g., visionOS->visionos)
self.assertEqual(res.system.lower(), sys.platform)
# Use the platform-specific version method
platform_ver = getattr(platform, f"{sys.platform}_ver")
self.assertEqual(res.release, platform_ver().release)
else:
self.assertEqual(res.system, "")
self.assertEqual(res.release, "")
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_webbrowser.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ def test_open_new_tab(self):
arguments=[f'openURL({URL},new-tab)'])


@unittest.skipUnless(sys.platform == "ios", "Test only applicable to iOS")
@unittest.skipUnless(sys.platform in {"ios", "visionOS"},
"Test only applicable to iOS and visionOS")
class IOSBrowserTest(unittest.TestCase):
def _obj_ref(self, *args):
# Construct a string representation of the arguments that can be used
Expand Down
8 changes: 5 additions & 3 deletions Lib/webbrowser.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,8 @@ def register_standard_browsers():
# macOS can use below Unix support (but we prefer using the macOS
# specific stuff)

if sys.platform == "ios":
if sys.platform in {"ios", "visionos"}:
# iOS and visionOS provide a browser; tvOS and watchOS don't.
register("iosbrowser", None, IOSBrowser(), preferred=True)

if sys.platform == "serenityos":
Expand Down Expand Up @@ -653,9 +654,10 @@ def open(self, url, new=0, autoraise=True):
return not rc

#
# Platform support for iOS
# Platform support for Apple Mobile platforms that provide a browser
# (i.e., iOS and visionOS)
#
if sys.platform == "ios":
if sys.platform in {"ios", "visionos"}:
from _ios_support import objc
if objc:
# If objc exists, we know ctypes is also importable.
Expand Down
Loading