Repository: pypa/setuptools
Pull request #1175 (2017-10-15 17:55:36)

Build meta: fixes and cleanups
Attached are some minor cleanups and fixes to the build_meta module that I added in #1143.


Patch:
diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py
index 54f2987bf..609ea1e51 100644
--- a/setuptools/build_meta.py
+++ b/setuptools/build_meta.py
@@ -65,10 +65,11 @@ def _run_setup(setup_script='setup.py'):
     # Note that we can reuse our build directory between calls
     # Correctness comes first, then optimization later
     __file__ = setup_script
+    __name__ = '__main__'
     f = getattr(tokenize, 'open', open)(__file__)
     code = f.read().replace('\\r\\n', '\\n')
     f.close()
-    exec(compile(code, __file__, 'exec'))
+    exec(compile(code, __file__, 'exec'), locals())
 
 
 def _fix_config(config_settings):
@@ -92,6 +93,11 @@ def _get_build_requires(config_settings):
     return requirements
 
 
+def _get_immediate_subdirectories(a_dir):
+    return [name for name in os.listdir(a_dir)
+            if os.path.isdir(os.path.join(a_dir, name))]
+
+
 def get_requires_for_build_wheel(config_settings=None):
     config_settings = _fix_config(config_settings)
     return _get_build_requires(config_settings)
@@ -105,11 +111,29 @@ def get_requires_for_build_sdist(config_settings=None):
 def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
     sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory]
     _run_setup()
+    
+    dist_info_directory = metadata_directory
+    while True:    
+        dist_infos = [f for f in os.listdir(dist_info_directory)
+                      if f.endswith('.dist-info')]
+
+        if len(dist_infos) == 0 and \
+                len(_get_immediate_subdirectories(dist_info_directory)) == 1:
+            dist_info_directory = os.path.join(
+                dist_info_directory, os.listdir(dist_info_directory)[0])
+            continue
+
+        assert len(dist_infos) == 1
+        break
+
+    # PEP 517 requires that the .dist-info directory be placed in the
+    # metadata_directory. To comply, we MUST copy the directory to the root
+    if dist_info_directory != metadata_directory:
+        shutil.move(
+            os.path.join(dist_info_directory, dist_infos[0]),
+            metadata_directory)
+        shutil.rmtree(dist_info_directory, ignore_errors=True)
 
-    dist_infos = [f for f in os.listdir(metadata_directory)
-                  if f.endswith('.dist-info')]
-
-    assert len(dist_infos) == 1
     return dist_infos[0]
 
 
diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py
index c6c6dacb7..c45258fa0 100644
--- a/setuptools/command/dist_info.py
+++ b/setuptools/command/dist_info.py
@@ -4,7 +4,6 @@ As defined in the wheel specification
 """
 
 import os
-import shutil
 
 from distutils.core import Command
 from distutils import log
@@ -27,14 +26,11 @@ class dist_info(Command):
 
     def run(self):
         egg_info = self.get_finalized_command('egg_info')
+        egg_info.egg_base = self.egg_base
+        egg_info.finalize_options()
         egg_info.run()
         dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info'
         log.info("creating '{}'".format(os.path.abspath(dist_info_dir)))
 
         bdist_wheel = self.get_finalized_command('bdist_wheel')
         bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir)
-
-        if self.egg_base:
-            destination = os.path.join(self.egg_base, dist_info_dir)
-            log.info("creating '{}'".format(os.path.abspath(destination)))
-            shutil.move(dist_info_dir, destination)


Test patch:
diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py
index 69a700c2c..659c1a658 100644
--- a/setuptools/tests/test_build_meta.py
+++ b/setuptools/tests/test_build_meta.py
@@ -42,22 +42,55 @@ class BuildBackendCaller(BuildBackendBase):
         return getattr(mod, name)(*args, **kw)
 
 
-@pytest.fixture
-def build_backend(tmpdir):
-    defn = {
-        'setup.py': DALS("""
-            __import__('setuptools').setup(
-                name='foo',
-                py_modules=['hello'],
-                setup_requires=['six'],
-            )
-            """),
-        'hello.py': DALS("""
-            def run():
-                print('hello')
-            """),
-    }
-    build_files(defn, prefix=str(tmpdir))
+defns = [{
+            'setup.py': DALS("""
+                __import__('setuptools').setup(
+                    name='foo',
+                    py_modules=['hello'],
+                    setup_requires=['six'],
+                )
+                """),
+            'hello.py': DALS("""
+                def run():
+                    print('hello')
+                """),
+        },
+        {
+            'setup.py': DALS("""
+                assert __name__ == '__main__'
+                __import__('setuptools').setup(
+                    name='foo',
+                    py_modules=['hello'],
+                    setup_requires=['six'],
+                )
+                """),
+            'hello.py': DALS("""
+                def run():
+                    print('hello')
+                """),
+        },
+        {
+            'setup.py': DALS("""
+                variable = True
+                def function():
+                    return variable
+                assert variable
+                __import__('setuptools').setup(
+                    name='foo',
+                    py_modules=['hello'],
+                    setup_requires=['six'],
+                )
+                """),
+            'hello.py': DALS("""
+                def run():
+                    print('hello')
+                """),
+        }]
+
+
+@pytest.fixture(params=defns)
+def build_backend(tmpdir, request):
+    build_files(request.param, prefix=str(tmpdir))
     with tmpdir.as_cwd():
         yield BuildBackend(cwd='.')