aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_capi/test_misc.py16
-rw-r--r--Lib/test/test_import/__init__.py86
-rw-r--r--Lib/test/test_importlib/extension/test_finder.py25
-rw-r--r--Lib/test/test_importlib/extension/test_loader.py56
-rw-r--r--Lib/test/test_importlib/test_util.py11
-rw-r--r--Lib/test/test_importlib/util.py6
6 files changed, 152 insertions, 48 deletions
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index d3fcd0b59df..7365ead1c47 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -2056,6 +2056,13 @@ class SubinterpreterTest(unittest.TestCase):
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if support.is_apple_mobile:
+ loader = "AppleFrameworkLoader"
+ else:
+ loader = "ExtensionFileLoader"
+
script = textwrap.dedent(f"""
import importlib.machinery
import importlib.util
@@ -2063,7 +2070,7 @@ class SubinterpreterTest(unittest.TestCase):
fullname = '_test_module_state_shared'
origin = importlib.util.find_spec('_testmultiphase').origin
- loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
+ loader = importlib.machinery.{loader}(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
attr_id = str(id(module.Error)).encode()
@@ -2371,7 +2378,12 @@ class Test_ModuleStateAccess(unittest.TestCase):
def setUp(self):
fullname = '_testmultiphase_meth_state_access' # XXX
origin = importlib.util.find_spec('_testmultiphase').origin
- loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if support.is_apple_mobile:
+ loader = importlib.machinery.AppleFrameworkLoader(fullname, origin)
+ else:
+ loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index 7b0126226c4..4deed7f3ba2 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -5,7 +5,11 @@ import json
import importlib.util
from importlib._bootstrap_external import _get_sourcefile
from importlib.machinery import (
- BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader,
+ AppleFrameworkLoader,
+ BuiltinImporter,
+ ExtensionFileLoader,
+ FrozenImporter,
+ SourceFileLoader,
)
import marshal
import os
@@ -25,7 +29,7 @@ import _imp
from test.support import os_helper
from test.support import (
- STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten,
+ STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten,
is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS)
from test.support.import_helper import (
forget, make_legacy_pyc, unlink, unload, ready_to_import,
@@ -66,6 +70,7 @@ def _require_loader(module, loader, skip):
MODULE_KINDS = {
BuiltinImporter: 'built-in',
ExtensionFileLoader: 'extension',
+ AppleFrameworkLoader: 'framework extension',
FrozenImporter: 'frozen',
SourceFileLoader: 'pure Python',
}
@@ -91,7 +96,12 @@ def require_builtin(module, *, skip=False):
assert module.__spec__.origin == 'built-in', module.__spec__
def require_extension(module, *, skip=False):
- _require_loader(module, ExtensionFileLoader, skip)
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if is_apple_mobile:
+ _require_loader(module, AppleFrameworkLoader, skip)
+ else:
+ _require_loader(module, ExtensionFileLoader, skip)
def require_frozen(module, *, skip=True):
module = _require_loader(module, FrozenImporter, skip)
@@ -134,7 +144,8 @@ if _testsinglephase is not None:
# it to its nominal state.
sys.modules.pop('_testsinglephase', None)
_orig._clear_globals()
- _testinternalcapi.clear_extension('_testsinglephase', _orig.__file__)
+ origin = _orig.__spec__.origin
+ _testinternalcapi.clear_extension('_testsinglephase', origin)
import _testsinglephase
@@ -360,7 +371,7 @@ class ImportTests(unittest.TestCase):
self.assertEqual(cm.exception.path, _testcapi.__file__)
self.assertRegex(
str(cm.exception),
- r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)"
+ r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|fwork|pyd)\)"
)
else:
self.assertEqual(
@@ -1689,6 +1700,14 @@ class SubinterpImportTests(unittest.TestCase):
os.set_blocking(r, False)
return (r, w)
+ def create_extension_loader(self, modname, filename):
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if is_apple_mobile:
+ return AppleFrameworkLoader(modname, filename)
+ else:
+ return ExtensionFileLoader(modname, filename)
+
def import_script(self, name, fd, filename=None, check_override=None):
override_text = ''
if check_override is not None:
@@ -1697,12 +1716,19 @@ class SubinterpImportTests(unittest.TestCase):
_imp._override_multi_interp_extensions_check({check_override})
'''
if filename:
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if is_apple_mobile:
+ loader = "AppleFrameworkLoader"
+ else:
+ loader = "ExtensionFileLoader"
+
return textwrap.dedent(f'''
from importlib.util import spec_from_loader, module_from_spec
- from importlib.machinery import ExtensionFileLoader
+ from importlib.machinery import {loader}
import os, sys
{override_text}
- loader = ExtensionFileLoader({name!r}, {filename!r})
+ loader = {loader}({name!r}, {filename!r})
spec = spec_from_loader({name!r}, loader)
try:
module = module_from_spec(spec)
@@ -1883,7 +1909,7 @@ class SubinterpImportTests(unittest.TestCase):
def test_multi_init_extension_non_isolated_compat(self):
modname = '_test_non_isolated'
filename = _testmultiphase.__file__
- loader = ExtensionFileLoader(modname, filename)
+ loader = self.create_extension_loader(modname, filename)
spec = importlib.util.spec_from_loader(modname, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
@@ -1901,7 +1927,7 @@ class SubinterpImportTests(unittest.TestCase):
def test_multi_init_extension_per_interpreter_gil_compat(self):
modname = '_test_shared_gil_only'
filename = _testmultiphase.__file__
- loader = ExtensionFileLoader(modname, filename)
+ loader = self.create_extension_loader(modname, filename)
spec = importlib.util.spec_from_loader(modname, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
@@ -2034,10 +2060,25 @@ class SinglephaseInitTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
spec = importlib.util.find_spec(cls.NAME)
- from importlib.machinery import ExtensionFileLoader
- cls.FILE = spec.origin
cls.LOADER = type(spec.loader)
- assert cls.LOADER is ExtensionFileLoader
+
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader, and we need to differentiate between the
+ # spec.origin and the original file location.
+ if is_apple_mobile:
+ assert cls.LOADER is AppleFrameworkLoader
+
+ cls.ORIGIN = spec.origin
+ with open(spec.origin + ".origin", "r") as f:
+ cls.FILE = os.path.join(
+ os.path.dirname(sys.executable),
+ f.read().strip()
+ )
+ else:
+ assert cls.LOADER is ExtensionFileLoader
+
+ cls.ORIGIN = spec.origin
+ cls.FILE = spec.origin
# Start fresh.
cls.clean_up()
@@ -2053,14 +2094,15 @@ class SinglephaseInitTests(unittest.TestCase):
@classmethod
def clean_up(cls):
name = cls.NAME
- filename = cls.FILE
if name in sys.modules:
if hasattr(sys.modules[name], '_clear_globals'):
- assert sys.modules[name].__file__ == filename
+ assert sys.modules[name].__file__ == cls.FILE, \
+ f"{sys.modules[name].__file__} != {cls.FILE}"
+
sys.modules[name]._clear_globals()
del sys.modules[name]
# Clear all internally cached data for the extension.
- _testinternalcapi.clear_extension(name, filename)
+ _testinternalcapi.clear_extension(name, cls.ORIGIN)
#########################
# helpers
@@ -2068,7 +2110,7 @@ class SinglephaseInitTests(unittest.TestCase):
def add_module_cleanup(self, name):
def clean_up():
# Clear all internally cached data for the extension.
- _testinternalcapi.clear_extension(name, self.FILE)
+ _testinternalcapi.clear_extension(name, self.ORIGIN)
self.addCleanup(clean_up)
def _load_dynamic(self, name, path):
@@ -2091,7 +2133,7 @@ class SinglephaseInitTests(unittest.TestCase):
except AttributeError:
already_loaded = self.already_loaded = {}
assert name not in already_loaded
- mod = self._load_dynamic(name, self.FILE)
+ mod = self._load_dynamic(name, self.ORIGIN)
self.assertNotIn(mod, already_loaded.values())
already_loaded[name] = mod
return types.SimpleNamespace(
@@ -2103,7 +2145,7 @@ class SinglephaseInitTests(unittest.TestCase):
def re_load(self, name, mod):
assert sys.modules[name] is mod
assert mod.__dict__ == mod.__dict__
- reloaded = self._load_dynamic(name, self.FILE)
+ reloaded = self._load_dynamic(name, self.ORIGIN)
return types.SimpleNamespace(
name=name,
module=reloaded,
@@ -2129,7 +2171,7 @@ class SinglephaseInitTests(unittest.TestCase):
name = {self.NAME!r}
if name in sys.modules:
sys.modules.pop(name)._clear_globals()
- _testinternalcapi.clear_extension(name, {self.FILE!r})
+ _testinternalcapi.clear_extension(name, {self.ORIGIN!r})
'''))
_interpreters.destroy(interpid)
self.addCleanup(clean_up)
@@ -2146,7 +2188,7 @@ class SinglephaseInitTests(unittest.TestCase):
postcleanup = f'''
{import_}
mod._clear_globals()
- _testinternalcapi.clear_extension(name, {self.FILE!r})
+ _testinternalcapi.clear_extension(name, {self.ORIGIN!r})
'''
try:
@@ -2184,7 +2226,7 @@ class SinglephaseInitTests(unittest.TestCase):
# mod.__name__ might not match, but the spec will.
self.assertEqual(mod.__spec__.name, loaded.name)
self.assertEqual(mod.__file__, self.FILE)
- self.assertEqual(mod.__spec__.origin, self.FILE)
+ self.assertEqual(mod.__spec__.origin, self.ORIGIN)
if not isolated:
self.assertTrue(issubclass(mod.error, Exception))
self.assertEqual(mod.int_const, 1969)
@@ -2578,7 +2620,7 @@ class SinglephaseInitTests(unittest.TestCase):
# First, load in the main interpreter but then completely clear it.
loaded_main = self.load(self.NAME)
loaded_main.module._clear_globals()
- _testinternalcapi.clear_extension(self.NAME, self.FILE)
+ _testinternalcapi.clear_extension(self.NAME, self.ORIGIN)
# At this point:
# * alive in 0 interpreters
diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py
index 3de120958fd..cdc8884d668 100644
--- a/Lib/test/test_importlib/extension/test_finder.py
+++ b/Lib/test/test_importlib/extension/test_finder.py
@@ -1,3 +1,4 @@
+from test.support import is_apple_mobile
from test.test_importlib import abc, util
machinery = util.import_importlib('importlib.machinery')
@@ -19,9 +20,27 @@ class FinderTests(abc.FinderTests):
)
def find_spec(self, fullname):
- importer = self.machinery.FileFinder(util.EXTENSIONS.path,
- (self.machinery.ExtensionFileLoader,
- self.machinery.EXTENSION_SUFFIXES))
+ if is_apple_mobile:
+ # Apple mobile platforms require a specialist loader that uses
+ # .fwork files as placeholders for the true `.so` files.
+ loaders = [
+ (
+ self.machinery.AppleFrameworkLoader,
+ [
+ ext.replace(".so", ".fwork")
+ for ext in self.machinery.EXTENSION_SUFFIXES
+ ]
+ )
+ ]
+ else:
+ loaders = [
+ (
+ self.machinery.ExtensionFileLoader,
+ self.machinery.EXTENSION_SUFFIXES
+ )
+ ]
+
+ importer = self.machinery.FileFinder(util.EXTENSIONS.path, *loaders)
return importer.find_spec(fullname)
diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py
index f4879e75847..7607f0e0857 100644
--- a/Lib/test/test_importlib/extension/test_loader.py
+++ b/Lib/test/test_importlib/extension/test_loader.py
@@ -1,3 +1,4 @@
+from test.support import is_apple_mobile
from test.test_importlib import abc, util
machinery = util.import_importlib('importlib.machinery')
@@ -23,8 +24,15 @@ class LoaderTests:
raise unittest.SkipTest(
f"{util.EXTENSIONS.name} is a builtin module"
)
- self.loader = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
- util.EXTENSIONS.file_path)
+
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if is_apple_mobile:
+ self.LoaderClass = self.machinery.AppleFrameworkLoader
+ else:
+ self.LoaderClass = self.machinery.ExtensionFileLoader
+
+ self.loader = self.LoaderClass(util.EXTENSIONS.name, util.EXTENSIONS.file_path)
def load_module(self, fullname):
with warnings.catch_warnings():
@@ -32,13 +40,11 @@ class LoaderTests:
return self.loader.load_module(fullname)
def test_equality(self):
- other = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
- util.EXTENSIONS.file_path)
+ other = self.LoaderClass(util.EXTENSIONS.name, util.EXTENSIONS.file_path)
self.assertEqual(self.loader, other)
def test_inequality(self):
- other = self.machinery.ExtensionFileLoader('_' + util.EXTENSIONS.name,
- util.EXTENSIONS.file_path)
+ other = self.LoaderClass('_' + util.EXTENSIONS.name, util.EXTENSIONS.file_path)
self.assertNotEqual(self.loader, other)
def test_load_module_API(self):
@@ -58,8 +64,7 @@ class LoaderTests:
('__package__', '')]:
self.assertEqual(getattr(module, attr), value)
self.assertIn(util.EXTENSIONS.name, sys.modules)
- self.assertIsInstance(module.__loader__,
- self.machinery.ExtensionFileLoader)
+ self.assertIsInstance(module.__loader__, self.LoaderClass)
# No extension module as __init__ available for testing.
test_package = None
@@ -86,7 +91,7 @@ class LoaderTests:
self.assertFalse(self.loader.is_package(util.EXTENSIONS.name))
for suffix in self.machinery.EXTENSION_SUFFIXES:
path = os.path.join('some', 'path', 'pkg', '__init__' + suffix)
- loader = self.machinery.ExtensionFileLoader('pkg', path)
+ loader = self.LoaderClass('pkg', path)
self.assertTrue(loader.is_package('pkg'))
@@ -101,6 +106,14 @@ class SinglePhaseExtensionModuleTests(abc.LoaderTests):
def setUp(self):
if not self.machinery.EXTENSION_SUFFIXES or not util.EXTENSIONS:
raise unittest.SkipTest("Requires dynamic loading support.")
+
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if is_apple_mobile:
+ self.LoaderClass = self.machinery.AppleFrameworkLoader
+ else:
+ self.LoaderClass = self.machinery.ExtensionFileLoader
+
self.name = '_testsinglephase'
if self.name in sys.builtin_module_names:
raise unittest.SkipTest(
@@ -109,8 +122,8 @@ class SinglePhaseExtensionModuleTests(abc.LoaderTests):
finder = self.machinery.FileFinder(None)
self.spec = importlib.util.find_spec(self.name)
assert self.spec
- self.loader = self.machinery.ExtensionFileLoader(
- self.name, self.spec.origin)
+
+ self.loader = self.LoaderClass(self.name, self.spec.origin)
def load_module(self):
with warnings.catch_warnings():
@@ -120,7 +133,7 @@ class SinglePhaseExtensionModuleTests(abc.LoaderTests):
def load_module_by_name(self, fullname):
# Load a module from the test extension by name.
origin = self.spec.origin
- loader = self.machinery.ExtensionFileLoader(fullname, origin)
+ loader = self.LoaderClass(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
@@ -137,8 +150,7 @@ class SinglePhaseExtensionModuleTests(abc.LoaderTests):
with self.assertRaises(AttributeError):
module.__path__
self.assertIs(module, sys.modules[self.name])
- self.assertIsInstance(module.__loader__,
- self.machinery.ExtensionFileLoader)
+ self.assertIsInstance(module.__loader__, self.LoaderClass)
# No extension module as __init__ available for testing.
test_package = None
@@ -182,6 +194,14 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests):
def setUp(self):
if not self.machinery.EXTENSION_SUFFIXES or not util.EXTENSIONS:
raise unittest.SkipTest("Requires dynamic loading support.")
+
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if is_apple_mobile:
+ self.LoaderClass = self.machinery.AppleFrameworkLoader
+ else:
+ self.LoaderClass = self.machinery.ExtensionFileLoader
+
self.name = '_testmultiphase'
if self.name in sys.builtin_module_names:
raise unittest.SkipTest(
@@ -190,8 +210,7 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests):
finder = self.machinery.FileFinder(None)
self.spec = importlib.util.find_spec(self.name)
assert self.spec
- self.loader = self.machinery.ExtensionFileLoader(
- self.name, self.spec.origin)
+ self.loader = self.LoaderClass(self.name, self.spec.origin)
def load_module(self):
# Load the module from the test extension.
@@ -202,7 +221,7 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests):
def load_module_by_name(self, fullname):
# Load a module from the test extension by name.
origin = self.spec.origin
- loader = self.machinery.ExtensionFileLoader(fullname, origin)
+ loader = self.LoaderClass(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
@@ -228,8 +247,7 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests):
with self.assertRaises(AttributeError):
module.__path__
self.assertIs(module, sys.modules[self.name])
- self.assertIsInstance(module.__loader__,
- self.machinery.ExtensionFileLoader)
+ self.assertIsInstance(module.__loader__, self.LoaderClass)
def test_functionality(self):
# Test basic functionality of stuff defined in an extension module.
diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py
index a09286806e5..a6a76e58976 100644
--- a/Lib/test/test_importlib/test_util.py
+++ b/Lib/test/test_importlib/test_util.py
@@ -707,13 +707,20 @@ class IncompatibleExtensionModuleRestrictionsTests(unittest.TestCase):
@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
def test_incomplete_multi_phase_init_module(self):
+ # Apple extensions must be distributed as frameworks. This requires
+ # a specialist loader.
+ if support.is_apple_mobile:
+ loader = "AppleFrameworkLoader"
+ else:
+ loader = "ExtensionFileLoader"
+
prescript = textwrap.dedent(f'''
from importlib.util import spec_from_loader, module_from_spec
- from importlib.machinery import ExtensionFileLoader
+ from importlib.machinery import {loader}
name = '_test_shared_gil_only'
filename = {_testmultiphase.__file__!r}
- loader = ExtensionFileLoader(name, filename)
+ loader = {loader}(name, filename)
spec = spec_from_loader(name, loader)
''')
diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py
index a900cc1dddf..89272484009 100644
--- a/Lib/test/test_importlib/util.py
+++ b/Lib/test/test_importlib/util.py
@@ -8,6 +8,7 @@ import os
import os.path
from test import support
from test.support import import_helper
+from test.support import is_apple_mobile
from test.support import os_helper
import unittest
import sys
@@ -43,6 +44,11 @@ else:
global EXTENSIONS
for path in sys.path:
for ext in machinery.EXTENSION_SUFFIXES:
+ # Apple mobile platforms mechanically load .so files,
+ # but the findable files are labelled .fwork
+ if is_apple_mobile:
+ ext = ext.replace(".so", ".fwork")
+
filename = EXTENSIONS.name + ext
file_path = os.path.join(path, filename)
if os.path.exists(file_path):