tests for helper functions used by import c from importlib import bootstrapexternal machinery import os path from types import moduletype simplenamespace import unittest import warnings from import util class fixupmoduletests def testnoloaderbutspecself loader object name hello path hello py spec machinery modulespecname loader ns spec spec bootstrapexternal fixupmodulens name path expected spec spec loader loader file path cached none self assertequalns expected def testnoloadernospecbutsourcelessself name hello path hello py ns bootstrapexternal fixupmodulens name path path expected file path cached path for key val in expected items with self subtestfkey val self assertequalnskey val spec nsspec self assertisinstancespec machinery modulespec self assertequalspec name name self assertequalspec origin os path abspathpath self assertequalspec cached os path abspathpath self assertisinstancespec loader machinery sourcelessfileloader self assertequalspec loader name name self assertequalspec loader path path self assertequalspec loader nsloader def testnoloadernospecbutsourceself name hello path hello py ns bootstrapexternal fixupmodulens name path expected file path cached none for key val in expected items with self subtestfkey val self assertequalnskey val spec nsspec self assertisinstancespec machinery modulespec self assertequalspec name name self assertequalspec origin os path abspathpath self assertisinstancespec loader machinery sourcefileloader self assertequalspec loader name name self assertequalspec loader path path self assertequalspec loader nsloader frozenfixupmoduletests sourcefixupmoduletests util testbothfixupmoduletests class testblessmyloaderunittest testcase gh86298 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 removeignore loader in favor of requiring spec loader def testgh86298noloaderandnospecself bar moduletype bar del bar loader del bar spec 20221006warsaw for backward compatibility with the implementation in warnings c this can t raise an attributeerror see blessmyloader in bootstrapexternal py if working with a module self assertraises attributeerror bootstrapexternal blessmyloader bar dict self assertisnonebootstrapexternal blessmyloaderbar dict def testgh86298loaderisnoneandnospecself bar moduletype bar bar loader none del bar spec 20221006warsaw for backward compatibility with the implementation in warnings c this can t raise an attributeerror see blessmyloader in bootstrapexternal py if working with a module self assertraises attributeerror bootstrapexternal blessmyloader bar dict self assertisnonebootstrapexternal blessmyloaderbar dict def testgh86298noloaderandspecisnoneself bar moduletype bar del bar loader bar spec none self assertraises valueerror bootstrapexternal blessmyloader bar dict def testgh86298loaderisnoneandspecisnoneself bar moduletype bar bar loader none bar spec none self assertraises valueerror bootstrapexternal blessmyloader bar dict def testgh86298loaderisnoneandspecloaderisnoneself bar moduletype bar bar loader none bar spec simplenamespaceloadernone self assertraises valueerror bootstrapexternal blessmyloader bar dict def testgh86298nospecself bar moduletype bar bar loader object del bar spec with warnings catchwarnings self assertwarns deprecationwarning bootstrapexternal blessmyloader bar dict def testgh86298specisnoneself bar moduletype bar bar loader object bar spec none with warnings catchwarnings self assertwarns deprecationwarning bootstrapexternal blessmyloader bar dict def testgh86298nospecloaderself bar moduletype bar bar loader object bar spec simplenamespace with warnings catchwarnings self assertwarns deprecationwarning bootstrapexternal blessmyloader bar dict def testgh86298loaderandspecloaderdisagreeself bar moduletype bar bar loader object bar spec simplenamespaceloaderobject with warnings catchwarnings self assertwarns deprecationwarning bootstrapexternal blessmyloader bar dict def testgh86298noloaderandnospecloaderself bar moduletype bar del bar loader bar spec simplenamespace self assertraises attributeerror bootstrapexternal blessmyloader bar dict def testgh86298noloaderwithspecloaderokayself bar moduletype bar del bar loader loader object bar spec simplenamespaceloaderloader self assertequal bootstrapexternal blessmyloaderbar dict loader if name main unittest main 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 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__ 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__
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):
    
    
    
    

    def test_gh86298_no_loader_and_no_spec(self):
        bar = ModuleType('bar')
        del bar.__loader__
        del bar.__spec__
        
        
        
        
        
        
        
        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__
        
        
        
        
        
        
        
        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()