5252
5353# Bootstrap-related code ######################################################
5454_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win' ,
55- _CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin' , 'darwin'
55+ _CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin' , 'darwin' , 'ios' , 'tvos' , 'watchos'
5656_CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
5757 + _CASE_INSENSITIVE_PLATFORMS_STR_KEY )
5858
@@ -81,6 +81,11 @@ def _pack_uint32(x):
8181 return (int (x ) & 0xFFFFFFFF ).to_bytes (4 , 'little' )
8282
8383
84+ def _unpack_uint64 (data ):
85+ """Convert 8 bytes in little-endian to an integer."""
86+ assert len (data ) == 8
87+ return int .from_bytes (data , 'little' )
88+
8489def _unpack_uint32 (data ):
8590 """Convert 4 bytes in little-endian to an integer."""
8691 assert len (data ) == 4
@@ -203,7 +208,7 @@ def _write_atomic(path, data, mode=0o666):
203208 try :
204209 # We first write data to a temporary file, and then use os.replace() to
205210 # perform an atomic rename.
206- with _io .FileIO (fd , 'wb' ) as file :
211+ with _io .open (fd , 'wb' ) as file :
207212 file .write (data )
208213 _os .replace (path_tmp , path )
209214 except OSError :
@@ -413,6 +418,7 @@ def _write_atomic(path, data, mode=0o666):
413418# Python 3.11a7 3492 (make POP_JUMP_IF_NONE/NOT_NONE/TRUE/FALSE relative)
414419# Python 3.11a7 3493 (Make JUMP_IF_TRUE_OR_POP/JUMP_IF_FALSE_OR_POP relative)
415420# Python 3.11a7 3494 (New location info table)
421+ # Python 3.11b4 3495 (Set line number of module's RESUME instr to 0 per PEP 626)
416422# Python 3.12a1 3500 (Remove PRECALL opcode)
417423# Python 3.12a1 3501 (YIELD_VALUE oparg == stack_depth)
418424# Python 3.12a1 3502 (LOAD_FAST_CHECK, no NULL-check in LOAD_FAST)
@@ -445,8 +451,30 @@ def _write_atomic(path, data, mode=0o666):
445451# Python 3.12b1 3529 (Inline list/dict/set comprehensions)
446452# Python 3.12b1 3530 (Shrink the LOAD_SUPER_ATTR caches)
447453# Python 3.12b1 3531 (Add PEP 695 changes)
448-
449- # Python 3.13 will start with 3550
454+ # Python 3.13a1 3550 (Plugin optimizer support)
455+ # Python 3.13a1 3551 (Compact superinstructions)
456+ # Python 3.13a1 3552 (Remove LOAD_FAST__LOAD_CONST and LOAD_CONST__LOAD_FAST)
457+ # Python 3.13a1 3553 (Add SET_FUNCTION_ATTRIBUTE)
458+ # Python 3.13a1 3554 (more efficient bytecodes for f-strings)
459+ # Python 3.13a1 3555 (generate specialized opcodes metadata from bytecodes.c)
460+ # Python 3.13a1 3556 (Convert LOAD_CLOSURE to a pseudo-op)
461+ # Python 3.13a1 3557 (Make the conversion to boolean in jumps explicit)
462+ # Python 3.13a1 3558 (Reorder the stack items for CALL)
463+ # Python 3.13a1 3559 (Generate opcode IDs from bytecodes.c)
464+ # Python 3.13a1 3560 (Add RESUME_CHECK instruction)
465+ # Python 3.13a1 3561 (Add cache entry to branch instructions)
466+ # Python 3.13a1 3562 (Assign opcode IDs for internal ops in separate range)
467+ # Python 3.13a1 3563 (Add CALL_KW and remove KW_NAMES)
468+ # Python 3.13a1 3564 (Removed oparg from YIELD_VALUE, changed oparg values of RESUME)
469+ # Python 3.13a1 3565 (Oparg of YIELD_VALUE indicates whether it is in a yield-from)
470+ # Python 3.13a1 3566 (Emit JUMP_NO_INTERRUPT instead of JUMP for non-loop no-lineno cases)
471+ # Python 3.13a1 3567 (Reimplement line number propagation by the compiler)
472+ # Python 3.13a1 3568 (Change semantics of END_FOR)
473+ # Python 3.13a5 3569 (Specialize CONTAINS_OP)
474+ # Python 3.13a6 3570 (Add __firstlineno__ class attribute)
475+ # Python 3.13b1 3571 (Fix miscompilation of private names in generic classes)
476+
477+ # Python 3.14 will start with 3600
450478
451479# Please don't copy-paste the same pre-release tag for new entries above!!!
452480# You should always use the *upcoming* tag. For example, if 3.12a6 came out
@@ -461,7 +489,7 @@ def _write_atomic(path, data, mode=0o666):
461489# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
462490# in PC/launcher.c must also be updated.
463491
464- MAGIC_NUMBER = (3531 ).to_bytes (2 , 'little' ) + b'\r \n '
492+ MAGIC_NUMBER = (3571 ).to_bytes (2 , 'little' ) + b'\r \n '
465493
466494_RAW_MAGIC_NUMBER = int .from_bytes (MAGIC_NUMBER , 'little' ) # For import.c
467495
@@ -535,7 +563,8 @@ def cache_from_source(path, debug_override=None, *, optimization=None):
535563 # Strip initial drive from a Windows path. We know we have an absolute
536564 # path here, so the second part of the check rules out a POSIX path that
537565 # happens to contain a colon at the second character.
538- if head [1 ] == ':' and head [0 ] not in path_separators :
566+ # Slicing avoids issues with an empty (or short) `head`.
567+ if head [1 :2 ] == ':' and head [0 :1 ] not in path_separators :
539568 head = head [2 :]
540569
541570 # Strip initial path separator from `head` to complete the conversion
@@ -1437,7 +1466,7 @@ class PathFinder:
14371466 @staticmethod
14381467 def invalidate_caches ():
14391468 """Call the invalidate_caches() method on all path entry finders
1440- stored in sys.path_importer_caches (where implemented)."""
1469+ stored in sys.path_importer_cache (where implemented)."""
14411470 for name , finder in list (sys .path_importer_cache .items ()):
14421471 # Drop entry if finder name is a relative path. The current
14431472 # working directory may have changed.
@@ -1449,6 +1478,9 @@ def invalidate_caches():
14491478 # https://bugs.python.org/issue45703
14501479 _NamespacePath ._epoch += 1
14511480
1481+ from importlib .metadata import MetadataPathFinder
1482+ MetadataPathFinder .invalidate_caches ()
1483+
14521484 @staticmethod
14531485 def _path_hooks (path ):
14541486 """Search sys.path_hooks for a finder for 'path'."""
@@ -1690,6 +1722,52 @@ def __repr__(self):
16901722 return f'FileFinder({ self .path !r} )'
16911723
16921724
1725+ class AppleFrameworkLoader (ExtensionFileLoader ):
1726+ """A loader for modules that have been packaged as frameworks for
1727+ compatibility with Apple's iOS App Store policies.
1728+ """
1729+ def create_module (self , spec ):
1730+ # If the ModuleSpec has been created by the FileFinder, it will have
1731+ # been created with an origin pointing to the .fwork file. We need to
1732+ # redirect this to the location in the Frameworks folder, using the
1733+ # content of the .fwork file.
1734+ if spec .origin .endswith (".fwork" ):
1735+ with _io .FileIO (spec .origin , 'r' ) as file :
1736+ framework_binary = file .read ().decode ().strip ()
1737+ bundle_path = _path_split (sys .executable )[0 ]
1738+ spec .origin = _path_join (bundle_path , framework_binary )
1739+
1740+ # If the loader is created based on the spec for a loaded module, the
1741+ # path will be pointing at the Framework location. If this occurs,
1742+ # get the original .fwork location to use as the module's __file__.
1743+ if self .path .endswith (".fwork" ):
1744+ path = self .path
1745+ else :
1746+ with _io .FileIO (self .path + ".origin" , 'r' ) as file :
1747+ origin = file .read ().decode ().strip ()
1748+ bundle_path = _path_split (sys .executable )[0 ]
1749+ path = _path_join (bundle_path , origin )
1750+
1751+ module = _bootstrap ._call_with_frames_removed (_imp .create_dynamic , spec )
1752+
1753+ _bootstrap ._verbose_message (
1754+ "Apple framework extension module {!r} loaded from {!r} (path {!r})" ,
1755+ spec .name ,
1756+ spec .origin ,
1757+ path ,
1758+ )
1759+
1760+ # Ensure that the __file__ points at the .fwork location
1761+ try :
1762+ module .__file__ = path
1763+ except AttributeError :
1764+ # Not important enough to report.
1765+ # (The error is also ignored in _bootstrap._init_module_attrs or
1766+ # import_run_extension in import.c)
1767+ pass
1768+
1769+ return module
1770+
16931771# Import setup ###############################################################
16941772
16951773def _fix_up_module (ns , name , pathname , cpathname = None ):
@@ -1722,10 +1800,17 @@ def _get_supported_file_loaders():
17221800
17231801 Each item is a tuple (loader, suffixes).
17241802 """
1725- extensions = ExtensionFileLoader , _imp .extension_suffixes ()
1803+ extension_loaders = []
1804+ if hasattr (_imp , 'create_dynamic' ):
1805+ if sys .platform in {"ios" , "tvos" , "watchos" }:
1806+ extension_loaders = [(AppleFrameworkLoader , [
1807+ suffix .replace (".so" , ".fwork" )
1808+ for suffix in _imp .extension_suffixes ()
1809+ ])]
1810+ extension_loaders .append ((ExtensionFileLoader , _imp .extension_suffixes ()))
17261811 source = SourceFileLoader , SOURCE_SUFFIXES
17271812 bytecode = SourcelessFileLoader , BYTECODE_SUFFIXES
1728- return [ extensions , source , bytecode ]
1813+ return extension_loaders + [ source , bytecode ]
17291814
17301815
17311816def _set_bootstrap_module (_bootstrap_module ):
0 commit comments