Repository: pypa/setuptools

Issue:
setuptools wheel install will fail if a data dir is a subdirectory in a package
With the new wheel support, I ran into an issue where if `data_files` specifies a subdirectory in a package, `setuptools` will fail on moving the data.  This worked in previous versions of setuptools w/o wheel support, and also works with pip install.

Perhaps this is not a supported use case (should `package_data` be used instead?)

I was able to work around the issue by removing the subdirectory, but in case someone else runs into this, here is a repro test case that can be added to `test_wheel.py`


```
    dict(
        id='data_in_package',
        file_defs={
            'foo': {
                '__init__.py': '',
                'data_dir': {
                    'data.txt': DALS(
                        '''
                        Some data...
                        '''
                    ),
                }
            }
        },
        setup_kwargs=dict(
            packages=['foo'],
            data_files=[('foo/data_dir', ['foo/data_dir/data.txt'])],
        ),
        install_tree=DALS(
            '''
            foo-1.0-py{py_version}.egg/
            |-- EGG-INFO/
            |  |-- DESCRIPTION.rst
            |  |-- PKG-INFO
            |  |-- RECORD
            |  |-- WHEEL
            |  |-- metadata.json
            |  |-- top_level.txt
            |-- foo/
            |  |-- __init__.py
            |  |-- data_dir/
            |     |-- data.txt
            '''
        ),
    ),
```

In the test case, `foo` is a package and `/foo/data_dir/` is a data dir. Since `foo` already exists as a package, the `os.rename` fails, even though `/foo/data_dir/` does not exist. Should it check if the directory already exists?

The error looks something like the following (on OSX):

```
                for entry in os.listdir(subdir):
                    os.rename(os.path.join(subdir, entry),
>                             os.path.join(destination_eggdir, entry))
E                   OSError: [Errno 66] Directory not empty: '/var/folders/07/c66dj8613n37ssnxsvyz8dcm0000gn/T/tmpybp6f4ft/foo-1.0-py3.5.egg/foo-1.0.data/data/foo' -> '/var/folders/07/c66dj8613n37ssnxsvyz8dcm0000gn/T/tmpybp6f4ft/foo-1.0-py3.5.egg/foo'
```






Discussion:

Resolving patch:
diff --git a/setuptools/wheel.py b/setuptools/wheel.py
--- a/setuptools/wheel.py
+++ b/setuptools/wheel.py
@@ -28,6 +28,28 @@
 '''
 
 
+def unpack(src_dir, dst_dir):
+    '''Move everything under `src_dir` to `dst_dir`, and delete the former.'''
+    for dirpath, dirnames, filenames in os.walk(src_dir):
+        subdir = os.path.relpath(dirpath, src_dir)
+        for f in filenames:
+            src = os.path.join(dirpath, f)
+            dst = os.path.join(dst_dir, subdir, f)
+            os.renames(src, dst)
+        for n, d in reversed(list(enumerate(dirnames))):
+            src = os.path.join(dirpath, d)
+            dst = os.path.join(dst_dir, subdir, d)
+            if not os.path.exists(dst):
+                # Directory does not exist in destination,
+                # rename it and prune it from os.walk list.
+                os.renames(src, dst)
+                del dirnames[n]
+    # Cleanup.
+    for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True):
+        assert not filenames
+        os.rmdir(dirpath)
+
+
 class Wheel(object):
 
     def __init__(self, filename):
@@ -125,10 +147,7 @@ def raw_req(req):
                 os.path.join(dist_data, d)
                 for d in ('data', 'headers', 'purelib', 'platlib')
             )):
-                for entry in os.listdir(subdir):
-                    os.rename(os.path.join(subdir, entry),
-                              os.path.join(destination_eggdir, entry))
-                os.rmdir(subdir)
+                unpack(subdir, destination_eggdir)
             if os.path.exists(dist_data):
                 os.rmdir(dist_data)
             # Fix namespace packages.


Test patch:
diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py
--- a/setuptools/tests/test_wheel.py
+++ b/setuptools/tests/test_wheel.py
@@ -444,6 +444,42 @@ def __repr__(self):
             '''),
     ),
 
+    dict(
+        id='data_in_package',
+        file_defs={
+            'foo': {
+                '__init__.py': '',
+                'data_dir': {
+                    'data.txt': DALS(
+                        '''
+                        Some data...
+                        '''
+                    ),
+                }
+            }
+        },
+        setup_kwargs=dict(
+            packages=['foo'],
+            data_files=[('foo/data_dir', ['foo/data_dir/data.txt'])],
+        ),
+        install_tree=DALS(
+            '''
+            foo-1.0-py{py_version}.egg/
+            |-- EGG-INFO/
+            |  |-- DESCRIPTION.rst
+            |  |-- PKG-INFO
+            |  |-- RECORD
+            |  |-- WHEEL
+            |  |-- metadata.json
+            |  |-- top_level.txt
+            |-- foo/
+            |  |-- __init__.py
+            |  |-- data_dir/
+            |  |  |-- data.txt
+            '''
+        ),
+    ),
+
 )
 
 @pytest.mark.parametrize(