Repository: pypa/setuptools

Issue:
build_meta breaks some setup.py scripts (e.g. numpy and pygame)
Setup:
* Setuptools 40.6.2
* Python 3.7.2

Some build scripts use `sys.argv[0]` to change the working directory to the parent directory of setup.py. For example, the setup.py script of numpy-1.15.4 contains the following code: 

```
src_path = os.path.dirname(os.path.abspath(sys.argv[0]))
old_path = os.getcwd()
os.chdir(src_path)
```

However,`sys.argv[0]` is an empty string, setup.py is called from setuptools.build_meta. Then `os.path.abspath()`, is the working directory and `os.path.dirname()`  its parent directory. This changes the current directory to the parent directory of the current path and breaks relative paths in the setup.py script.

While manually running `python3 setup.py bdist_wheel` succedes, calling `setuptools.build_meta.build_wheel()` in the Python REPL then gives the following error:
```
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/setuptools/build_meta.py", line 158, in build_wheel
    _run_setup()
  File "/usr/local/lib/python3.7/site-packages/setuptools/build_meta.py", line 85, in _run_setup
    exec(compile(code, __file__, 'exec'), locals())
  File "setup.py", line 403, in <module>
  File "setup.py", line 349, in setup_package
  File "setup.py", line 147, in write_version_py
FileNotFoundError: [Errno 2] No such file or directory: 'numpy/version.py'
``` 

A similar error occurs for pygame-1.9.4. Maybe I overlooked something, but it seems that the problem originates from the way setuptools.build_meta calls setup.py. 
build_meta breaks some setup.py scripts (e.g. numpy and pygame)
Setup:
* Setuptools 40.6.2
* Python 3.7.2

Some build scripts use `sys.argv[0]` to change the working directory to the parent directory of setup.py. For example, the setup.py script of numpy-1.15.4 contains the following code: 

```
src_path = os.path.dirname(os.path.abspath(sys.argv[0]))
old_path = os.getcwd()
os.chdir(src_path)
```

However,`sys.argv[0]` is an empty string, setup.py is called from setuptools.build_meta. Then `os.path.abspath()`, is the working directory and `os.path.dirname()`  its parent directory. This changes the current directory to the parent directory of the current path and breaks relative paths in the setup.py script.

While manually running `python3 setup.py bdist_wheel` succedes, calling `setuptools.build_meta.build_wheel()` in the Python REPL then gives the following error:
```
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/setuptools/build_meta.py", line 158, in build_wheel
    _run_setup()
  File "/usr/local/lib/python3.7/site-packages/setuptools/build_meta.py", line 85, in _run_setup
    exec(compile(code, __file__, 'exec'), locals())
  File "setup.py", line 403, in <module>
  File "setup.py", line 349, in setup_package
  File "setup.py", line 147, in write_version_py
FileNotFoundError: [Errno 2] No such file or directory: 'numpy/version.py'
``` 

A similar error occurs for pygame-1.9.4. Maybe I overlooked something, but it seems that the problem originates from the way setuptools.build_meta calls setup.py. 


Discussion:
I think we can try to fix this in `setuptools.build_meta:__legacy__`, but not in `setuptools.build_meta`.
I think we can try to fix this in `setuptools.build_meta:__legacy__`, but not in `setuptools.build_meta`.

Resolving patch:
diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py
--- a/setuptools/build_meta.py
+++ b/setuptools/build_meta.py
@@ -232,6 +232,12 @@ def run_setup(self, setup_script='setup.py'):
         if script_dir not in sys.path:
             sys.path.insert(0, script_dir)
 
+        # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to
+        # get the directory of the source code. They expect it to refer to the
+        # setup.py script.
+        sys_argv_0 = sys.argv[0]
+        sys.argv[0] = setup_script
+
         try:
             super(_BuildMetaLegacyBackend,
                   self).run_setup(setup_script=setup_script)
@@ -242,6 +248,7 @@ def run_setup(self, setup_script='setup.py'):
             # the original path so that the path manipulation does not persist
             # within the hook after run_setup is called.
             sys.path[:] = sys_path
+            sys.argv[0] = sys_argv_0
 
 # The primary backend
 _BACKEND = _BuildMetaBackend()


Test patch:
diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py
--- a/setuptools/tests/test_build_meta.py
+++ b/setuptools/tests/test_build_meta.py
@@ -385,6 +385,28 @@ def run():
 
         assert expected == sorted(actual)
 
+    _sys_argv_0_passthrough = {
+        'setup.py': DALS("""
+            import os
+            import sys
+
+            __import__('setuptools').setup(
+                name='foo',
+                version='0.0.0',
+            )
+
+            sys_argv = os.path.abspath(sys.argv[0])
+            file_path = os.path.abspath('setup.py')
+            assert sys_argv == file_path
+            """)
+    }
+
+    def test_sys_argv_passthrough(self, tmpdir_cwd):
+        build_files(self._sys_argv_0_passthrough)
+        build_backend = self.get_build_backend()
+        with pytest.raises(AssertionError):
+            build_backend.build_sdist("temp")
+
 
 class TestBuildMetaLegacyBackend(TestBuildMetaBackend):
     backend_name = 'setuptools.build_meta:__legacy__'
@@ -396,3 +418,9 @@ def test_build_sdist_relative_path_import(self, tmpdir_cwd):
 
         build_backend = self.get_build_backend()
         build_backend.build_sdist("temp")
+
+    def test_sys_argv_passthrough(self, tmpdir_cwd):
+        build_files(self._sys_argv_0_passthrough)
+
+        build_backend = self.get_build_backend()
+        build_backend.build_sdist("temp")