"""Tests for helper functions used by import.c ."""
from importlib import _bootstrap_external, machinery
import os.path
from types import ModuleType, SimpleNamespace
import unittest
import warnings
from .. import util
class FixUpModuleTests:
def test_no_loader_but_spec(self):
loader = object()
name = "hello"
path = "hello.py"
spec = machinery.ModuleSpec(name, loader)
ns = {"__spec__": spec}
_bootstrap_external._fix_up_module(ns, name, path)
expected = {"__spec__": spec, "__loader__": loader, "__file__": path,
"__cached__": None}
self.assertEqual(ns, expected)
def test_no_loader_no_spec_but_sourceless(self):
name = "hello"
path = "hello.py"
ns = {}
_bootstrap_external._fix_up_module(ns, name, path, path)
expected = {"__file__": path, "__cached__": path}
for key, val in expected.items():
with self.subTest(f"{key}: {val}"):
self.assertEqual(ns[key], val)
spec = ns["__spec__"]
self.assertIsInstance(spec, machinery.ModuleSpec)
self.assertEqual(spec.name, name)
self.assertEqual(spec.origin, os.path.abspath(path))
self.assertEqual(spec.cached, os.path.abspath(path))
self.assertIsInstance(spec.loader, machinery.SourcelessFileLoader)
self.assertEqual(spec.loader.name, name)
self.assertEqual(spec.loader.path, path)
self.assertEqual(spec.loader, ns["__loader__"])
def test_no_loader_no_spec_but_source(self):
name = "hello"
path = "hello.py"
ns = {}
_bootstrap_external._fix_up_module(ns, name, path)
expected = {"__file__": path, "__cached__": None}
for key, val in expected.items():
with self.subTest(f"{key}: {val}"):
self.assertEqual(ns[key], val)
spec = ns["__spec__"]
self.assertIsInstance(spec, machinery.ModuleSpec)
self.assertEqual(spec.name, name)
self.assertEqual(spec.origin, os.path.abspath(path))
self.assertIsInstance(spec.loader, machinery.SourceFileLoader)
self.assertEqual(spec.loader.name, name)
self.assertEqual(spec.loader.path, path)
self.assertEqual(spec.loader, ns["__loader__"])
FrozenFixUpModuleTests, SourceFixUpModuleTests = util.test_both(FixUpModuleTests)
class TestBlessMyLoader(unittest.TestCase):
# GH#86298 is part of the migration away from module attributes and toward
# __spec__ attributes. There are several cases to test here. This will
# have to change in Python 3.14 when we actually remove/ignore __loader__
# in favor of requiring __spec__.loader.
def test_gh86298_no_loader_and_no_spec(self):
bar = ModuleType('bar')
del bar.__loader__
del bar.__spec__
# 2022-10-06(warsaw): For backward compatibility with the
# implementation in _warnings.c, this can't raise an
# AttributeError. See _bless_my_loader() in _bootstrap_external.py
# If working with a module:
## self.assertRaises(
## AttributeError, _bootstrap_external._bless_my_loader,
## bar.__dict__)
self.assertIsNone(_bootstrap_external._bless_my_loader(bar.__dict__))
def test_gh86298_loader_is_none_and_no_spec(self):
bar = ModuleType('bar')
bar.__loader__ = None
del bar.__spec__
# 2022-10-06(warsaw): For backward compatibility with the
# implementation in _warnings.c, this can't raise an
# AttributeError. See _bless_my_loader() in _bootstrap_external.py
# If working with a module:
## self.assertRaises(
## AttributeError, _bootstrap_external._bless_my_loader,
## bar.__dict__)
self.assertIsNone(_bootstrap_external._bless_my_loader(bar.__dict__))
def test_gh86298_no_loader_and_spec_is_none(self):
bar = ModuleType('bar')
del bar.__loader__
bar.__spec__ = None
self.assertRaises(
ValueError,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_loader_is_none_and_spec_is_none(self):
bar = ModuleType('bar')
bar.__loader__ = None
bar.__spec__ = None
self.assertRaises(
ValueError,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_loader_is_none_and_spec_loader_is_none(self):
bar = ModuleType('bar')
bar.__loader__ = None
bar.__spec__ = SimpleNamespace(loader=None)
self.assertRaises(
ValueError,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_no_spec(self):
bar = ModuleType('bar')
bar.__loader__ = object()
del bar.__spec__
with warnings.catch_warnings():
self.assertWarns(
DeprecationWarning,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_spec_is_none(self):
bar = ModuleType('bar')
bar.__loader__ = object()
bar.__spec__ = None
with warnings.catch_warnings():
self.assertWarns(
DeprecationWarning,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_no_spec_loader(self):
bar = ModuleType('bar')
bar.__loader__ = object()
bar.__spec__ = SimpleNamespace()
with warnings.catch_warnings():
self.assertWarns(
DeprecationWarning,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_loader_and_spec_loader_disagree(self):
bar = ModuleType('bar')
bar.__loader__ = object()
bar.__spec__ = SimpleNamespace(loader=object())
with warnings.catch_warnings():
self.assertWarns(
DeprecationWarning,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_no_loader_and_no_spec_loader(self):
bar = ModuleType('bar')
del bar.__loader__
bar.__spec__ = SimpleNamespace()
self.assertRaises(
AttributeError,
_bootstrap_external._bless_my_loader, bar.__dict__)
def test_gh86298_no_loader_with_spec_loader_okay(self):
bar = ModuleType('bar')
del bar.__loader__
loader = object()
bar.__spec__ = SimpleNamespace(loader=loader)
self.assertEqual(
_bootstrap_external._bless_my_loader(bar.__dict__),
loader)
if __name__ == "__main__":
unittest.main()