pep 366 main module explicit relative imports specifies the semantics for the package attribute on modules this attribute is used when available to detect which package a module belongs to instead of using the typical pathname test use of package supersedes the use of namepath to calculate what package a module belongs to the basic algorithm is package def resolvenamename package level level 1 base package rsplit level0 return 0 1 formatbase name but since there is no guarantee that package has been set or not been set to none none there has to be a way to calculate the attribute s value name def calcpackagecallername haspath if haspath return callername else return callername rsplit 10 then the normal algorithm for relative name imports can proceed as if package had been set package name none if package isn t defined fall back on spec parent raise a deprecationwarning if package spec parent because package is a new feature it is not always set by a loader import will set it as needed to help with the transition to relying on package for a toplevel module package is set to none toplevel for a package name is used for package package for submodules the value is name rsplit 10 submodule toplevel package submodule use of __package__ supersedes the use of __name__ __path__ to calculate what package a module belongs to the basic algorithm is __package__ def resolve_name name package level level 1 base package rsplit level 0 return 0 1 format base name but since there is no guarantee that __package__ has been set or not been set to none none there has to be a way to calculate the attribute s value __name__ def calc_package caller_name has___path__ if has__path__ return caller_name else return caller_name rsplit 1 0 then the normal algorithm for relative name imports can proceed as if __package__ had been set __package__ __name__ none if __package__ isn t defined fall back on __spec__ parent raise a deprecationwarning if __package__ __spec__ parent because __package__ is a new feature it is not always set by a loader import will set it as needed to help with the transition to relying on __package__ for a top level module __package__ is set to none top level for a package __name__ is used for __package__ package for submodules the value is __name__ rsplit 1 0 submodule top level package submodule
import unittest
import warnings
from test.test_importlib import util


class Using__package__:

    

    def import_module(self, globals_):
        with self.mock_modules('pkg.__init__', 'pkg.fake') as importer:
            with util.import_state(meta_path=[importer]):
                self.__import__('pkg.fake')
                module = self.__import__('',
                                         globals=globals_,
                                         fromlist=['attr'], level=2)
        return module

    def test_using___package__(self):
        
        module = self.import_module({'__package__': 'pkg.fake'})
        self.assertEqual(module.__name__, 'pkg')

    def test_using___name__(self):
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            module = self.import_module({'__name__': 'pkg.fake',
                                         '__path__': []})
        self.assertEqual(module.__name__, 'pkg')

    def test_warn_when_using___name__(self):
        with self.assertWarns(ImportWarning):
            self.import_module({'__name__': 'pkg.fake', '__path__': []})

    def test_None_as___package__(self):
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            module = self.import_module({
                '__name__': 'pkg.fake', '__path__': [], '__package__': None })
        self.assertEqual(module.__name__, 'pkg')

    def test_spec_fallback(self):
        
        module = self.import_module({'__spec__': FakeSpec('pkg.fake')})
        self.assertEqual(module.__name__, 'pkg')

    def test_warn_when_package_and_spec_disagree(self):
        
        with self.assertWarns(DeprecationWarning):
            self.import_module({'__package__': 'pkg.fake',
                                '__spec__': FakeSpec('pkg.fakefake')})

    def test_bad__package__(self):
        globals = {'__package__': '<not real>'}
        with self.assertRaises(ModuleNotFoundError):
            self.__import__('', globals, {}, ['relimport'], 1)

    def test_bunk__package__(self):
        globals = {'__package__': 42}
        with self.assertRaises(TypeError):
            self.__import__('', globals, {}, ['relimport'], 1)


class FakeSpec:
    def __init__(self, parent):
        self.parent = parent


class Using__package__PEP451(Using__package__):
    mock_modules = util.mock_spec


(Frozen_UsingPackagePEP451,
 Source_UsingPackagePEP451
 ) = util.test_both(Using__package__PEP451, __import__=util.__import__)


class Setting__package__:

    

    __import__ = util.__import__['Source']

    
    def test_top_level(self):
        with self.mock_modules('top_level') as mock:
            with util.import_state(meta_path=[mock]):
                del mock['top_level'].__package__
                module = self.__import__('top_level')
                self.assertEqual(module.__package__, '')

    
    def test_package(self):
        with self.mock_modules('pkg.__init__') as mock:
            with util.import_state(meta_path=[mock]):
                del mock['pkg'].__package__
                module = self.__import__('pkg')
                self.assertEqual(module.__package__, 'pkg')

    
    def test_submodule(self):
        with self.mock_modules('pkg.__init__', 'pkg.mod') as mock:
            with util.import_state(meta_path=[mock]):
                del mock['pkg.mod'].__package__
                pkg = self.__import__('pkg.mod')
                module = getattr(pkg, 'mod')
                self.assertEqual(module.__package__, 'pkg')


class Setting__package__PEP451(Setting__package__, unittest.TestCase):
    mock_modules = util.mock_spec


if __name__ == '__main__':
    unittest.main()