We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pants-provided-Python for Pex CLI doesn't work in docker environments
**Describe the bug**
Trying to use docker_environment to run a test on a machine without Python installed will result in an error:

```
Failed to find a compatible PEX_PYTHON=.python-build-standalone/c12164f0e9228ec20704c1aba97eb31b8e2a482d41943d541cc8e3a9e84f7349/bin/python3.

No interpreters could be found on the system.
```

**Pants version**
2.20

**OS**
Linux host and linux container

**Additional info**



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/python/pants/core/util_rules/adhoc_binaries.py`
Content:
```
1 # Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2 # Licensed under the Apache License, Version 2.0 (see LICENSE).
3 
4 from __future__ import annotations
5 
6 import os
7 import sys
8 from dataclasses import dataclass
9 from textwrap import dedent  # noqa: PNT20
10 
11 from pants.core.subsystems.python_bootstrap import PythonBootstrapSubsystem
12 from pants.core.util_rules.environments import EnvironmentTarget, LocalEnvironmentTarget
13 from pants.core.util_rules.system_binaries import SEARCH_PATHS, BashBinary, TarBinary
14 from pants.engine.env_vars import EnvironmentVars, EnvironmentVarsRequest
15 from pants.engine.fs import DownloadFile
16 from pants.engine.internals.native_engine import Digest, FileDigest
17 from pants.engine.internals.selectors import Get
18 from pants.engine.platform import Platform
19 from pants.engine.process import Process, ProcessCacheScope, ProcessResult
20 from pants.engine.rules import collect_rules, rule
21 from pants.util.frozendict import FrozenDict
22 from pants.util.logging import LogLevel
23 
24 
25 @dataclass(frozen=True)
26 class PythonBuildStandaloneBinary:
27     """A Python interpreter for use by `@rule` code as an alternative to BashBinary scripts.
28 
29     This interpreter is provided by Python Build Standalone https://gregoryszorc.com/docs/python-build-standalone/main/,
30     which has a few caveats. Namely it doesn't play nicely with third-party sdists. Meaning Pants'
31     scripts being run by Python Build Standalone should avoid third-party sdists.
32     """
33 
34     _CACHE_DIRNAME = "python_build_standalone"
35     _SYMLINK_DIRNAME = ".python-build-standalone"
36     APPEND_ONLY_CACHES = FrozenDict({_CACHE_DIRNAME: _SYMLINK_DIRNAME})
37 
38     path: str  # The absolute path to a Python executable
39 
40 
41 # NB: These private types are solely so we can test the docker-path using the local
42 # environment.
43 class _PythonBuildStandaloneBinary(PythonBuildStandaloneBinary):
44     pass
45 
46 
47 class _DownloadPythonBuildStandaloneBinaryRequest:
48     pass
49 
50 
51 @rule
52 async def get_python_for_scripts(env_tgt: EnvironmentTarget) -> PythonBuildStandaloneBinary:
53     if env_tgt.val is None or isinstance(env_tgt.val, LocalEnvironmentTarget):
54         return PythonBuildStandaloneBinary(sys.executable)
55 
56     result = await Get(_PythonBuildStandaloneBinary, _DownloadPythonBuildStandaloneBinaryRequest())
57 
58     return PythonBuildStandaloneBinary(result.path)
59 
60 
61 @rule(desc="Downloading Python for scripts", level=LogLevel.TRACE)
62 async def download_python_binary(
63     _: _DownloadPythonBuildStandaloneBinaryRequest,
64     platform: Platform,
65     tar_binary: TarBinary,
66     python_bootstrap: PythonBootstrapSubsystem,
67     bash: BashBinary,
68 ) -> _PythonBuildStandaloneBinary:
69     url, fingerprint, bytelen = python_bootstrap.internal_python_build_standalone_info[
70         platform.value
71     ]
72 
73     filename = url.rsplit("/", 1)[-1]
74     python_archive = await Get(
75         Digest,
76         DownloadFile(
77             url,
78             FileDigest(
79                 fingerprint=fingerprint,
80                 serialized_bytes_length=bytelen,
81             ),
82         ),
83     )
84 
85     download_result = await Get(
86         ProcessResult,
87         Process(
88             argv=[tar_binary.path, "-xvf", filename],
89             input_digest=python_archive,
90             env={"PATH": os.pathsep.join(SEARCH_PATHS)},
91             description="Extract Pants' execution Python",
92             level=LogLevel.DEBUG,
93             output_directories=("python",),
94         ),
95     )
96 
97     installation_root = f"{PythonBuildStandaloneBinary._SYMLINK_DIRNAME}/{download_result.output_digest.fingerprint}"
98 
99     # NB: This is similar to what we do for every Python provider. We should refactor these into
100     # some shared code to centralize the behavior.
101     installation_script = dedent(
102         f"""\
103         if [ ! -f "{installation_root}/DONE" ]; then
104             cp -r python "{installation_root}"
105             touch "{installation_root}/DONE"
106         fi
107     """
108     )
109 
110     env_vars = await Get(EnvironmentVars, EnvironmentVarsRequest(["PATH"]))
111     await Get(
112         ProcessResult,
113         Process(
114             [bash.path, "-c", installation_script],
115             level=LogLevel.DEBUG,
116             input_digest=download_result.output_digest,
117             description="Install Python for Pants usage",
118             env={"PATH": env_vars.get("PATH", "")},
119             append_only_caches=PythonBuildStandaloneBinary.APPEND_ONLY_CACHES,
120             # Don't cache, we want this to always be run so that we can assume for the rest of the
121             # session the named_cache destination for this Python is valid, as the Python ecosystem
122             # mainly assumes absolute paths for Python interpreters.
123             cache_scope=ProcessCacheScope.PER_SESSION,
124         ),
125     )
126 
127     return _PythonBuildStandaloneBinary(f"{installation_root}/bin/python3")
128 
129 
130 @dataclass(frozen=True)
131 class GunzipBinaryRequest:
132     pass
133 
134 
135 @dataclass(frozen=True)
136 class GunzipBinary:
137     python_binary: PythonBuildStandaloneBinary
138 
139     def extract_archive_argv(self, archive_path: str, extract_path: str) -> tuple[str, ...]:
140         archive_name = os.path.basename(archive_path)
141         dest_file_name = os.path.splitext(archive_name)[0]
142         dest_path = os.path.join(extract_path, dest_file_name)
143         script = dedent(
144             f"""
145             import gzip
146             import shutil
147             with gzip.GzipFile(filename={archive_path!r}, mode="rb") as source:
148                 with open({dest_path!r}, "wb") as dest:
149                     shutil.copyfileobj(source, dest)
150             """
151         )
152         return (self.python_binary.path, "-c", script)
153 
154 
155 @rule
156 def find_gunzip(python_binary: PythonBuildStandaloneBinary) -> GunzipBinary:
157     return GunzipBinary(python_binary)
158 
159 
160 @rule
161 async def find_gunzip_wrapper(_: GunzipBinaryRequest, gunzip: GunzipBinary) -> GunzipBinary:
162     return gunzip
163 
164 
165 def rules():
166     return collect_rules()
167
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/python/pants/core/util_rules/adhoc_binaries.py b/src/python/pants/core/util_rules/adhoc_binaries.py
--- a/src/python/pants/core/util_rules/adhoc_binaries.py
+++ b/src/python/pants/core/util_rules/adhoc_binaries.py
@@ -104,11 +104,12 @@
             cp -r python "{installation_root}"
             touch "{installation_root}/DONE"
         fi
+        echo "$(realpath "{installation_root}")/bin/python3"
     """
     )
 
     env_vars = await Get(EnvironmentVars, EnvironmentVarsRequest(["PATH"]))
-    await Get(
+    result = await Get(
         ProcessResult,
         Process(
             [bash.path, "-c", installation_script],
@@ -124,7 +125,7 @@
         ),
     )
 
-    return _PythonBuildStandaloneBinary(f"{installation_root}/bin/python3")
+    return _PythonBuildStandaloneBinary(result.stdout.decode().splitlines()[-1].strip())
 
 
 @dataclass(frozen=True)

{"golden_diff": "diff --git a/src/python/pants/core/util_rules/adhoc_binaries.py b/src/python/pants/core/util_rules/adhoc_binaries.py\n--- a/src/python/pants/core/util_rules/adhoc_binaries.py\n+++ b/src/python/pants/core/util_rules/adhoc_binaries.py\n@@ -104,11 +104,12 @@\n             cp -r python \"{installation_root}\"\n             touch \"{installation_root}/DONE\"\n         fi\n+        echo \"$(realpath \"{installation_root}\")/bin/python3\"\n     \"\"\"\n     )\n \n     env_vars = await Get(EnvironmentVars, EnvironmentVarsRequest([\"PATH\"]))\n-    await Get(\n+    result = await Get(\n         ProcessResult,\n         Process(\n             [bash.path, \"-c\", installation_script],\n@@ -124,7 +125,7 @@\n         ),\n     )\n \n-    return _PythonBuildStandaloneBinary(f\"{installation_root}/bin/python3\")\n+    return _PythonBuildStandaloneBinary(result.stdout.decode().splitlines()[-1].strip())\n \n \n @dataclass(frozen=True)\n", "issue": "Pants-provided-Python for Pex CLI doesn't work in docker environments\n**Describe the bug**\r\nTrying to use docker_environment to run a test on a machine without Python installed will result in an error:\r\n\r\n```\r\nFailed to find a compatible PEX_PYTHON=.python-build-standalone/c12164f0e9228ec20704c1aba97eb31b8e2a482d41943d541cc8e3a9e84f7349/bin/python3.\r\n\r\nNo interpreters could be found on the system.\r\n```\r\n\r\n**Pants version**\r\n2.20\r\n\r\n**OS**\r\nLinux host and linux container\r\n\r\n**Additional info**\r\n\r\n\n", "before_files": [{"content": "# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom dataclasses import dataclass\nfrom textwrap import dedent  # noqa: PNT20\n\nfrom pants.core.subsystems.python_bootstrap import PythonBootstrapSubsystem\nfrom pants.core.util_rules.environments import EnvironmentTarget, LocalEnvironmentTarget\nfrom pants.core.util_rules.system_binaries import SEARCH_PATHS, BashBinary, TarBinary\nfrom pants.engine.env_vars import EnvironmentVars, EnvironmentVarsRequest\nfrom pants.engine.fs import DownloadFile\nfrom pants.engine.internals.native_engine import Digest, FileDigest\nfrom pants.engine.internals.selectors import Get\nfrom pants.engine.platform import Platform\nfrom pants.engine.process import Process, ProcessCacheScope, ProcessResult\nfrom pants.engine.rules import collect_rules, rule\nfrom pants.util.frozendict import FrozenDict\nfrom pants.util.logging import LogLevel\n\n\n@dataclass(frozen=True)\nclass PythonBuildStandaloneBinary:\n    \"\"\"A Python interpreter for use by `@rule` code as an alternative to BashBinary scripts.\n\n    This interpreter is provided by Python Build Standalone https://gregoryszorc.com/docs/python-build-standalone/main/,\n    which has a few caveats. Namely it doesn't play nicely with third-party sdists. Meaning Pants'\n    scripts being run by Python Build Standalone should avoid third-party sdists.\n    \"\"\"\n\n    _CACHE_DIRNAME = \"python_build_standalone\"\n    _SYMLINK_DIRNAME = \".python-build-standalone\"\n    APPEND_ONLY_CACHES = FrozenDict({_CACHE_DIRNAME: _SYMLINK_DIRNAME})\n\n    path: str  # The absolute path to a Python executable\n\n\n# NB: These private types are solely so we can test the docker-path using the local\n# environment.\nclass _PythonBuildStandaloneBinary(PythonBuildStandaloneBinary):\n    pass\n\n\nclass _DownloadPythonBuildStandaloneBinaryRequest:\n    pass\n\n\n@rule\nasync def get_python_for_scripts(env_tgt: EnvironmentTarget) -> PythonBuildStandaloneBinary:\n    if env_tgt.val is None or isinstance(env_tgt.val, LocalEnvironmentTarget):\n        return PythonBuildStandaloneBinary(sys.executable)\n\n    result = await Get(_PythonBuildStandaloneBinary, _DownloadPythonBuildStandaloneBinaryRequest())\n\n    return PythonBuildStandaloneBinary(result.path)\n\n\n@rule(desc=\"Downloading Python for scripts\", level=LogLevel.TRACE)\nasync def download_python_binary(\n    _: _DownloadPythonBuildStandaloneBinaryRequest,\n    platform: Platform,\n    tar_binary: TarBinary,\n    python_bootstrap: PythonBootstrapSubsystem,\n    bash: BashBinary,\n) -> _PythonBuildStandaloneBinary:\n    url, fingerprint, bytelen = python_bootstrap.internal_python_build_standalone_info[\n        platform.value\n    ]\n\n    filename = url.rsplit(\"/\", 1)[-1]\n    python_archive = await Get(\n        Digest,\n        DownloadFile(\n            url,\n            FileDigest(\n                fingerprint=fingerprint,\n                serialized_bytes_length=bytelen,\n            ),\n        ),\n    )\n\n    download_result = await Get(\n        ProcessResult,\n        Process(\n            argv=[tar_binary.path, \"-xvf\", filename],\n            input_digest=python_archive,\n            env={\"PATH\": os.pathsep.join(SEARCH_PATHS)},\n            description=\"Extract Pants' execution Python\",\n            level=LogLevel.DEBUG,\n            output_directories=(\"python\",),\n        ),\n    )\n\n    installation_root = f\"{PythonBuildStandaloneBinary._SYMLINK_DIRNAME}/{download_result.output_digest.fingerprint}\"\n\n    # NB: This is similar to what we do for every Python provider. We should refactor these into\n    # some shared code to centralize the behavior.\n    installation_script = dedent(\n        f\"\"\"\\\n        if [ ! -f \"{installation_root}/DONE\" ]; then\n            cp -r python \"{installation_root}\"\n            touch \"{installation_root}/DONE\"\n        fi\n    \"\"\"\n    )\n\n    env_vars = await Get(EnvironmentVars, EnvironmentVarsRequest([\"PATH\"]))\n    await Get(\n        ProcessResult,\n        Process(\n            [bash.path, \"-c\", installation_script],\n            level=LogLevel.DEBUG,\n            input_digest=download_result.output_digest,\n            description=\"Install Python for Pants usage\",\n            env={\"PATH\": env_vars.get(\"PATH\", \"\")},\n            append_only_caches=PythonBuildStandaloneBinary.APPEND_ONLY_CACHES,\n            # Don't cache, we want this to always be run so that we can assume for the rest of the\n            # session the named_cache destination for this Python is valid, as the Python ecosystem\n            # mainly assumes absolute paths for Python interpreters.\n            cache_scope=ProcessCacheScope.PER_SESSION,\n        ),\n    )\n\n    return _PythonBuildStandaloneBinary(f\"{installation_root}/bin/python3\")\n\n\n@dataclass(frozen=True)\nclass GunzipBinaryRequest:\n    pass\n\n\n@dataclass(frozen=True)\nclass GunzipBinary:\n    python_binary: PythonBuildStandaloneBinary\n\n    def extract_archive_argv(self, archive_path: str, extract_path: str) -> tuple[str, ...]:\n        archive_name = os.path.basename(archive_path)\n        dest_file_name = os.path.splitext(archive_name)[0]\n        dest_path = os.path.join(extract_path, dest_file_name)\n        script = dedent(\n            f\"\"\"\n            import gzip\n            import shutil\n            with gzip.GzipFile(filename={archive_path!r}, mode=\"rb\") as source:\n                with open({dest_path!r}, \"wb\") as dest:\n                    shutil.copyfileobj(source, dest)\n            \"\"\"\n        )\n        return (self.python_binary.path, \"-c\", script)\n\n\n@rule\ndef find_gunzip(python_binary: PythonBuildStandaloneBinary) -> GunzipBinary:\n    return GunzipBinary(python_binary)\n\n\n@rule\nasync def find_gunzip_wrapper(_: GunzipBinaryRequest, gunzip: GunzipBinary) -> GunzipBinary:\n    return gunzip\n\n\ndef rules():\n    return collect_rules()\n", "path": "src/python/pants/core/util_rules/adhoc_binaries.py"}], "after_files": [{"content": "# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom dataclasses import dataclass\nfrom textwrap import dedent  # noqa: PNT20\n\nfrom pants.core.subsystems.python_bootstrap import PythonBootstrapSubsystem\nfrom pants.core.util_rules.environments import EnvironmentTarget, LocalEnvironmentTarget\nfrom pants.core.util_rules.system_binaries import SEARCH_PATHS, BashBinary, TarBinary\nfrom pants.engine.env_vars import EnvironmentVars, EnvironmentVarsRequest\nfrom pants.engine.fs import DownloadFile\nfrom pants.engine.internals.native_engine import Digest, FileDigest\nfrom pants.engine.internals.selectors import Get\nfrom pants.engine.platform import Platform\nfrom pants.engine.process import Process, ProcessCacheScope, ProcessResult\nfrom pants.engine.rules import collect_rules, rule\nfrom pants.util.frozendict import FrozenDict\nfrom pants.util.logging import LogLevel\n\n\n@dataclass(frozen=True)\nclass PythonBuildStandaloneBinary:\n    \"\"\"A Python interpreter for use by `@rule` code as an alternative to BashBinary scripts.\n\n    This interpreter is provided by Python Build Standalone https://gregoryszorc.com/docs/python-build-standalone/main/,\n    which has a few caveats. Namely it doesn't play nicely with third-party sdists. Meaning Pants'\n    scripts being run by Python Build Standalone should avoid third-party sdists.\n    \"\"\"\n\n    _CACHE_DIRNAME = \"python_build_standalone\"\n    _SYMLINK_DIRNAME = \".python-build-standalone\"\n    APPEND_ONLY_CACHES = FrozenDict({_CACHE_DIRNAME: _SYMLINK_DIRNAME})\n\n    path: str  # The absolute path to a Python executable\n\n\n# NB: These private types are solely so we can test the docker-path using the local\n# environment.\nclass _PythonBuildStandaloneBinary(PythonBuildStandaloneBinary):\n    pass\n\n\nclass _DownloadPythonBuildStandaloneBinaryRequest:\n    pass\n\n\n@rule\nasync def get_python_for_scripts(env_tgt: EnvironmentTarget) -> PythonBuildStandaloneBinary:\n    if env_tgt.val is None or isinstance(env_tgt.val, LocalEnvironmentTarget):\n        return PythonBuildStandaloneBinary(sys.executable)\n\n    result = await Get(_PythonBuildStandaloneBinary, _DownloadPythonBuildStandaloneBinaryRequest())\n\n    return PythonBuildStandaloneBinary(result.path)\n\n\n@rule(desc=\"Downloading Python for scripts\", level=LogLevel.TRACE)\nasync def download_python_binary(\n    _: _DownloadPythonBuildStandaloneBinaryRequest,\n    platform: Platform,\n    tar_binary: TarBinary,\n    python_bootstrap: PythonBootstrapSubsystem,\n    bash: BashBinary,\n) -> _PythonBuildStandaloneBinary:\n    url, fingerprint, bytelen = python_bootstrap.internal_python_build_standalone_info[\n        platform.value\n    ]\n\n    filename = url.rsplit(\"/\", 1)[-1]\n    python_archive = await Get(\n        Digest,\n        DownloadFile(\n            url,\n            FileDigest(\n                fingerprint=fingerprint,\n                serialized_bytes_length=bytelen,\n            ),\n        ),\n    )\n\n    download_result = await Get(\n        ProcessResult,\n        Process(\n            argv=[tar_binary.path, \"-xvf\", filename],\n            input_digest=python_archive,\n            env={\"PATH\": os.pathsep.join(SEARCH_PATHS)},\n            description=\"Extract Pants' execution Python\",\n            level=LogLevel.DEBUG,\n            output_directories=(\"python\",),\n        ),\n    )\n\n    installation_root = f\"{PythonBuildStandaloneBinary._SYMLINK_DIRNAME}/{download_result.output_digest.fingerprint}\"\n\n    # NB: This is similar to what we do for every Python provider. We should refactor these into\n    # some shared code to centralize the behavior.\n    installation_script = dedent(\n        f\"\"\"\\\n        if [ ! -f \"{installation_root}/DONE\" ]; then\n            cp -r python \"{installation_root}\"\n            touch \"{installation_root}/DONE\"\n        fi\n        echo \"$(realpath \"{installation_root}\")/bin/python3\"\n    \"\"\"\n    )\n\n    env_vars = await Get(EnvironmentVars, EnvironmentVarsRequest([\"PATH\"]))\n    result = await Get(\n        ProcessResult,\n        Process(\n            [bash.path, \"-c\", installation_script],\n            level=LogLevel.DEBUG,\n            input_digest=download_result.output_digest,\n            description=\"Install Python for Pants usage\",\n            env={\"PATH\": env_vars.get(\"PATH\", \"\")},\n            append_only_caches=PythonBuildStandaloneBinary.APPEND_ONLY_CACHES,\n            # Don't cache, we want this to always be run so that we can assume for the rest of the\n            # session the named_cache destination for this Python is valid, as the Python ecosystem\n            # mainly assumes absolute paths for Python interpreters.\n            cache_scope=ProcessCacheScope.PER_SESSION,\n        ),\n    )\n\n    return _PythonBuildStandaloneBinary(result.stdout.decode().splitlines()[-1].strip())\n\n\n@dataclass(frozen=True)\nclass GunzipBinaryRequest:\n    pass\n\n\n@dataclass(frozen=True)\nclass GunzipBinary:\n    python_binary: PythonBuildStandaloneBinary\n\n    def extract_archive_argv(self, archive_path: str, extract_path: str) -> tuple[str, ...]:\n        archive_name = os.path.basename(archive_path)\n        dest_file_name = os.path.splitext(archive_name)[0]\n        dest_path = os.path.join(extract_path, dest_file_name)\n        script = dedent(\n            f\"\"\"\n            import gzip\n            import shutil\n            with gzip.GzipFile(filename={archive_path!r}, mode=\"rb\") as source:\n                with open({dest_path!r}, \"wb\") as dest:\n                    shutil.copyfileobj(source, dest)\n            \"\"\"\n        )\n        return (self.python_binary.path, \"-c\", script)\n\n\n@rule\ndef find_gunzip(python_binary: PythonBuildStandaloneBinary) -> GunzipBinary:\n    return GunzipBinary(python_binary)\n\n\n@rule\nasync def find_gunzip_wrapper(_: GunzipBinaryRequest, gunzip: GunzipBinary) -> GunzipBinary:\n    return gunzip\n\n\ndef rules():\n    return collect_rules()\n", "path": "src/python/pants/core/util_rules/adhoc_binaries.py"}]}