Repository: pypa/setuptools
Pull request #1861 (2019-10-07 21:03:05)

Fix empty namespace package wheel install
<!-- First time contributors: Take a moment to review https://setuptools.readthedocs.io/en/latest/developer-guide.html! -->
<!-- Remove sections if not applicable -->

## Summary of changes

Fix a corner case found with one of the tests when implementing #1830: handle installing a wheel with an empty namespace package.

### Pull Request Checklist
- [x] Changes have tests
- [x] News fragment added in changelog.d. See [documentation](http://setuptools.readthedocs.io/en/latest/developer-guide.html#making-a-pull-request) for details



Patch:
diff --git a/changelog.d/1860.doc.rst b/changelog.d/1860.doc.rst
deleted file mode 100644
index f3554643f..000000000
--- a/changelog.d/1860.doc.rst
+++ /dev/null
@@ -1,1 +0,0 @@
-Update documentation to mention the egg format is not supported by pip and dependency links support was dropped starting with pip 19.0.
diff --git a/changelog.d/1861.change.rst b/changelog.d/1861.change.rst
new file mode 100644
index 000000000..5a4e0a56a
--- /dev/null
+++ b/changelog.d/1861.change.rst
@@ -0,0 +1,1 @@
+Fix empty namespace package installation from wheel.
diff --git a/docs/setuptools.txt b/docs/setuptools.txt
index 26a3044e8..2e7fe3bd9 100644
--- a/docs/setuptools.txt
+++ b/docs/setuptools.txt
@@ -675,10 +675,6 @@ using ``setup.py develop``.)
 Dependencies that aren't in PyPI
 --------------------------------
 
-.. warning::
-    Dependency links support has been dropped by pip starting with version
-    19.0 (released 2019-01-22).
-
 If your project depends on packages that don't exist on PyPI, you may still be
 able to depend on them, as long as they are available for download as:
 
@@ -1693,9 +1689,6 @@ file locations.
 ``bdist_egg`` - Create a Python Egg for the project
 ===================================================
 
-.. warning::
-    **eggs** are deprecated in favor of wheels, and not supported by pip.
-
 This command generates a Python Egg (``.egg`` file) for the project.  Python
 Eggs are the preferred binary distribution format for EasyInstall, because they
 are cross-platform (for "pure" packages), directly importable, and contain
diff --git a/setuptools/_vendor/vendored.txt b/setuptools/_vendor/vendored.txt
index 5731b4244..379aae56e 100644
--- a/setuptools/_vendor/vendored.txt
+++ b/setuptools/_vendor/vendored.txt
@@ -1,4 +1,4 @@
 packaging==16.8
 pyparsing==2.2.1
 six==1.10.0
-ordered-set==3.1.1
+ordered-set
diff --git a/setuptools/wheel.py b/setuptools/wheel.py
index e11f0a1d9..22eec05ec 100644
--- a/setuptools/wheel.py
+++ b/setuptools/wheel.py
@@ -1,6 +1,7 @@
 """Wheels support."""
 
 from distutils.util import get_platform
+from distutils import log
 import email
 import itertools
 import os
@@ -162,11 +163,17 @@ class Wheel:
                 extras_require=extras_require,
             ),
         )
-        write_requirements(
-            setup_dist.get_command_obj('egg_info'),
-            None,
-            os.path.join(egg_info, 'requires.txt'),
-        )
+        # Temporarily disable info traces.
+        log_threshold = log._global_log.threshold
+        log.set_threshold(log.WARN)
+        try:
+            write_requirements(
+                setup_dist.get_command_obj('egg_info'),
+                None,
+                os.path.join(egg_info, 'requires.txt'),
+            )
+        finally:
+            log.set_threshold(log_threshold)
 
     @staticmethod
     def _move_data_entries(destination_eggdir, dist_data):
@@ -206,6 +213,8 @@ class Wheel:
             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):
+                if not os.path.exists(mod_dir):
+                    os.mkdir(mod_dir)
+                if not os.path.exists(mod_init):
                     with open(mod_init, 'w') as fp:
                         fp.write(NAMESPACE_PACKAGE_INIT)


Test patch:
diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py
index e85a4a7e8..d50816c22 100644
--- a/setuptools/tests/test_wheel.py
+++ b/setuptools/tests/test_wheel.py
@@ -450,6 +450,34 @@ WHEEL_INSTALL_TESTS = (
         }),
     ),
 
+    dict(
+        id='empty_namespace_package',
+        file_defs={
+            'foobar': {
+                '__init__.py': "__import__('pkg_resources').declare_namespace(__name__)",
+            },
+        },
+        setup_kwargs=dict(
+            namespace_packages=['foobar'],
+            packages=['foobar'],
+        ),
+        install_tree=flatten_tree({
+            'foo-1.0-py{py_version}.egg': [
+                'foo-1.0-py{py_version}-nspkg.pth',
+                {'EGG-INFO': [
+                    'PKG-INFO',
+                    'RECORD',
+                    'WHEEL',
+                    'namespace_packages.txt',
+                    'top_level.txt',
+                ]},
+                {'foobar': [
+                    '__init__.py',
+                ]},
+            ]
+        }),
+    ),
+
     dict(
         id='data_in_package',
         file_defs={