diff --git a/CHANGES.rst b/CHANGES.rst index d5fd66a376..3886854a1c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +v38.2.2 +------- + +* #1214: fix handling of namespace packages when installing + from a wheel. + v38.2.1 ------- diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py index 2e857253d5..408c357612 100644 --- a/setuptools/tests/test_wheel.py +++ b/setuptools/tests/test_wheel.py @@ -412,6 +412,38 @@ def __repr__(self): ), ), + dict( + id='namespace_package', + file_defs={ + 'foo': { + 'bar': { + '__init__.py': '' + }, + }, + }, + setup_kwargs=dict( + namespace_packages=['foo'], + packages=['foo.bar'], + ), + install_tree=DALS( + ''' + foo-1.0-py{py_version}.egg/ + |-- foo-1.0-py{py_version}-nspkg.pth + |-- EGG-INFO/ + | |-- DESCRIPTION.rst + | |-- PKG-INFO + | |-- RECORD + | |-- WHEEL + | |-- metadata.json + | |-- namespace_packages.txt + | |-- top_level.txt + |-- foo/ + | |-- __init__.py + | |-- bar/ + | | |-- __init__.py + '''), + ), + ) @pytest.mark.parametrize( diff --git a/setuptools/wheel.py b/setuptools/wheel.py index f711f38bae..c23272133f 100644 --- a/setuptools/wheel.py +++ b/setuptools/wheel.py @@ -20,6 +20,13 @@ )\.whl$""", re.VERBOSE).match +NAMESPACE_PACKAGE_INIT = '''\ +try: + __import__('pkg_resources').declare_namespace(__name__) +except ImportError: + __path__ = __import__('pkgutil').extend_path(__path__, __name__) +''' + class Wheel(object): @@ -124,3 +131,14 @@ def raw_req(req): os.rmdir(subdir) if os.path.exists(dist_data): os.rmdir(dist_data) + # Fix namespace packages. + namespace_packages = os.path.join(egg_info, 'namespace_packages.txt') + if os.path.exists(namespace_packages): + with open(namespace_packages) as fp: + namespace_packages = fp.read().split() + for mod in namespace_packages: + mod_dir = os.path.join(destination_eggdir, *mod.split('.')) + mod_init = os.path.join(mod_dir, '__init__.py') + if os.path.exists(mod_dir) and not os.path.exists(mod_init): + with open(mod_init, 'w') as fp: + fp.write(NAMESPACE_PACKAGE_INIT)