Repository: pypa/pip
File: src/pip/_internal/utils/setuptools_build.py (Python)

Code before:
# Shim to wrap setup.py invocation with setuptools
# Note that __file__ is handled via two {!r} *and* %r, to ensure that paths on
# Windows are correctly handled (it should be "C:\\Users" not "C:\Users").
_SETUPTOOLS_SHIM = textwrap.dedent(
    """
    exec(compile('''
    # This is <pip-setuptools-caller> -- a caller that pip uses to run setup.py
    #
    # - It imports setuptools before invoking setup.py, to enable projects that directly
    #   import from `distutils.core` to work with newer packaging standards.
    # - It provides a clear error message when setuptools is not installed.
    # - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
    #   setuptools doesn't think the script is `-c`. This avoids the following warning:
    #     manifest_maker: standard file '-c' not found".
    # - It generates a shim setup.py, for handling setup.cfg-only projects.
    import os, sys, tokenize, traceback

    try:
        import setuptools
    except ImportError as error:
        print(
            "ERROR: Can not execute `setup.py` since setuptools failed to import in "
            "the build environment with exception:",
            file=sys.stderr,
        )
        traceback.print_tb(error.__traceback__, file=sys.stderr)
        sys.exit(1)

    __file__ = %r
    sys.argv[0] = __file__

    if os.path.exists(__file__):
        filename = __file__
        with tokenize.open(__file__) as f:
            setup_py_code = f.read()
    else:
        filename = "<auto-generated setuptools caller>"
        setup_py_code = "from setuptools import setup; setup()"

    exec(compile(setup_py_code, filename, "exec"))
    ''' % ({!r},), "<pip-setuptools-caller>", "exec"))
    """
).rstrip()


def make_setuptools_shim_args(
    setup_py_path: str,
    global_options: Optional[Sequence[str]] = None,
    no_user_config: bool = False,
    unbuffered_output: bool = False,
) -> List[str]:

Review comment (suggestion):
```suggestion
        traceback.print_exc()
```

We should include the exception type and value as the traceback is confusing without them:

![image](https://github.com/user-attachments/assets/185f04e2-70ec-4333-9469-647fc0096b2a)

`traceback.print_exc()` is a shortcut that will present the currently handled exception in ~essentially the same way as Python itself. 

![image](https://github.com/user-attachments/assets/9ddf123b-a809-4129-93c9-818ea5dc00dd)

And yes, it outputs to stderr. I checked.

<details><summary>Proof</summary>
<p>

```py
import subprocess, sys

code = """
import traceback
try:
    import missing
except ModuleNotFoundError:
    traceback.print_exc()
"""

proc = subprocess.run([sys.executable, "-c", code], capture_output=True, encoding="utf-8")
print(f"{proc.stdout=}")
print(f"{proc.stderr=}")
```

```
$ python test.py
proc.stdout=''
proc.stderr='Traceback (most recent call last):\n  File "<string>", line 4, in <module>\nModuleNotFoundError: No module named \'missing\'\n'
```

</p>
</details> 

Code after:
# Shim to wrap setup.py invocation with setuptools
# Note that __file__ is handled via two {!r} *and* %r, to ensure that paths on
# Windows are correctly handled (it should be "C:\\Users" not "C:\Users").
_SETUPTOOLS_SHIM = textwrap.dedent(
    """
    exec(compile('''
    # This is <pip-setuptools-caller> -- a caller that pip uses to run setup.py
    #
    # - It imports setuptools before invoking setup.py, to enable projects that directly
    #   import from `distutils.core` to work with newer packaging standards.
    # - It provides a clear error message when setuptools is not installed.
    # - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
    #   setuptools doesn't think the script is `-c`. This avoids the following warning:
    #     manifest_maker: standard file '-c' not found".
    # - It generates a shim setup.py, for handling setup.cfg-only projects.
    import os, sys, tokenize, traceback

    try:
        import setuptools
    except ImportError:
        print(
            "ERROR: Can not execute `setup.py` since setuptools failed to import in "
            "the build environment with exception:",
            file=sys.stderr,
        )
        traceback.print_exc()
        sys.exit(1)

    __file__ = %r
    sys.argv[0] = __file__

    if os.path.exists(__file__):
        filename = __file__
        with tokenize.open(__file__) as f:
            setup_py_code = f.read()
    else:
        filename = "<auto-generated setuptools caller>"
        setup_py_code = "from setuptools import setup; setup()"

    exec(compile(setup_py_code, filename, "exec"))
    ''' % ({!r},), "<pip-setuptools-caller>", "exec"))
    """
).rstrip()


def make_setuptools_shim_args(
    setup_py_path: str,
    global_options: Optional[Sequence[str]] = None,
    no_user_config: bool = False,
    unbuffered_output: bool = False,
) -> List[str]: