We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`[pex].emit_warnings` docs show `&#x3E;` literally instead of  `>`
**Describe the bug**

https://www.pantsbuild.org/2.20/reference/subsystems/pex#emit_warnings

![image](https://github.com/pantsbuild/pants/assets/1203825/3c7f7152-3f56-4d74-9e49-fe5ad4d3e7ca)


**Pants version**
2.20

**OS**
N/A

**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/backend/python/util_rules/pex_environment.py`
Content:
```
1 # Copyright 2019 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 from dataclasses import dataclass
8 from pathlib import PurePath
9 from typing import Mapping
10 
11 from pants.core.subsystems.python_bootstrap import PythonBootstrap
12 from pants.core.util_rules import subprocess_environment, system_binaries
13 from pants.core.util_rules.adhoc_binaries import PythonBuildStandaloneBinary
14 from pants.core.util_rules.subprocess_environment import SubprocessEnvironmentVars
15 from pants.core.util_rules.system_binaries import BinaryPath
16 from pants.engine.engine_aware import EngineAwareReturnType
17 from pants.engine.rules import collect_rules, rule
18 from pants.option.global_options import NamedCachesDirOption
19 from pants.option.option_types import BoolOption, IntOption, StrListOption
20 from pants.option.subsystem import Subsystem
21 from pants.util.frozendict import FrozenDict
22 from pants.util.logging import LogLevel
23 from pants.util.memo import memoized_property
24 from pants.util.ordered_set import OrderedSet
25 from pants.util.strutil import softwrap
26 
27 
28 class PexSubsystem(Subsystem):
29     options_scope = "pex"
30     help = "How Pants uses Pex to run Python subprocesses."
31 
32     class EnvironmentAware(Subsystem.EnvironmentAware):
33         # TODO(#9760): We'll want to deprecate this in favor of a global option which allows for a
34         #  per-process override.
35 
36         env_vars_used_by_options = ("PATH",)
37 
38         _executable_search_paths = StrListOption(
39             default=["<PATH>"],
40             help=softwrap(
41                 """
42                 The PATH value that will be used by the PEX subprocess and any subprocesses it
43                 spawns.
44 
45                 The special string `"<PATH>"` will expand to the contents of the PATH env var.
46                 """
47             ),
48             advanced=True,
49             metavar="<binary-paths>",
50         )
51 
52         @memoized_property
53         def path(self) -> tuple[str, ...]:
54             def iter_path_entries():
55                 for entry in self._executable_search_paths:
56                     if entry == "<PATH>":
57                         path = self._options_env.get("PATH")
58                         if path:
59                             yield from path.split(os.pathsep)
60                     else:
61                         yield entry
62 
63             return tuple(OrderedSet(iter_path_entries()))
64 
65     _verbosity = IntOption(
66         default=0,
67         help="Set the verbosity level of PEX logging, from 0 (no logging) up to 9 (max logging).",
68         advanced=True,
69     )
70     venv_use_symlinks = BoolOption(
71         default=False,
72         help=softwrap(
73             """
74             When possible, use venvs whose site-packages directories are populated with symlinks.
75 
76             Enabling this can save space in the `--named-caches-dir` directory
77             and lead to slightly faster execution times for Pants Python goals. Some
78             distributions do not work with symlinked venvs though, so you may not be able to
79             enable this optimization as a result.
80             """
81         ),
82         advanced=True,
83     )
84     emit_warnings = BoolOption(
85         default=False,
86         help=softwrap(
87             """
88             If warnings from Pex should be logged by Pants to the console.
89 
90             Note: Pants uses Pex internally in some ways that trigger some warnings at the moment,
91             so enabling this may result in warnings not related to your code. See
92             <https://github.com/pantsbuild/pants/issues/20577> and
93             <https://github.com/pantsbuild/pants/issues/20586>.
94             """
95         ),
96     )
97 
98     @property
99     def verbosity(self) -> int:
100         level = self._verbosity
101         if level < 0 or level > 9:
102             raise ValueError("verbosity level must be between 0 and 9")
103         return level
104 
105 
106 @dataclass(frozen=True)
107 class PythonExecutable(BinaryPath, EngineAwareReturnType):
108     """The BinaryPath of a Python executable for user code, along with some extras."""
109 
110     append_only_caches: FrozenDict[str, str] = FrozenDict({})
111 
112     def __init__(
113         self,
114         path: str,
115         fingerprint: str | None = None,
116         append_only_caches: Mapping[str, str] = FrozenDict({}),
117     ) -> None:
118         object.__setattr__(self, "append_only_caches", FrozenDict(append_only_caches))
119         super().__init__(path, fingerprint)
120         self.__post_init__()
121 
122     def __post_init__(self) -> None:
123         if not PurePath(self.path).is_absolute():
124             raise ValueError(
125                 softwrap(
126                     f"""
127                     PythonExecutable expects the path to be absolute. Tools like Pex internalize the
128                     absolute path to Python (since `sys.executable` is expected to be absolute).
129 
130                     In order to ensure the cache key for Python process is "correct" (especially in
131                     remote cache/execution situations) we require the Python path is absolute.
132 
133                     Got: {self.path}
134                     """
135                 )
136             )
137 
138     def message(self) -> str:
139         return f"Selected {self.path} to run PEXes with."
140 
141 
142 @dataclass(frozen=True)
143 class PexEnvironment:
144     path: tuple[str, ...]
145     interpreter_search_paths: tuple[str, ...]
146     subprocess_environment_dict: FrozenDict[str, str]
147     named_caches_dir: PurePath
148     bootstrap_python: PythonBuildStandaloneBinary
149     venv_use_symlinks: bool = False
150 
151     _PEX_ROOT_DIRNAME = "pex_root"
152 
153     def in_sandbox(self, *, working_directory: str | None) -> CompletePexEnvironment:
154         pex_root = PurePath(".cache") / self._PEX_ROOT_DIRNAME
155         return CompletePexEnvironment(
156             _pex_environment=self,
157             pex_root=pex_root,
158             _working_directory=PurePath(working_directory) if working_directory else None,
159             append_only_caches=FrozenDict(
160                 **{self._PEX_ROOT_DIRNAME: str(pex_root)},
161                 **self.bootstrap_python.APPEND_ONLY_CACHES,
162             ),
163         )
164 
165     def in_workspace(self) -> CompletePexEnvironment:
166         # N.B.: When running in the workspace the engine doesn't offer an append_only_caches
167         # service to setup a symlink to our named cache for us. As such, we point the PEX_ROOT
168         # directly at the underlying append only cache in that case to re-use results there and
169         # to keep the workspace from being dirtied by the creation of a new Pex cache rooted
170         # there.
171         pex_root = self.named_caches_dir / self._PEX_ROOT_DIRNAME
172         return CompletePexEnvironment(
173             _pex_environment=self,
174             pex_root=pex_root,
175             _working_directory=None,
176             append_only_caches=self.bootstrap_python.APPEND_ONLY_CACHES,
177         )
178 
179     def venv_site_packages_copies_option(self, use_copies: bool) -> str:
180         if self.venv_use_symlinks and not use_copies:
181             return "--no-venv-site-packages-copies"
182         return "--venv-site-packages-copies"
183 
184 
185 @rule(desc="Prepare environment for running PEXes", level=LogLevel.DEBUG)
186 async def find_pex_python(
187     python_bootstrap: PythonBootstrap,
188     python_binary: PythonBuildStandaloneBinary,
189     pex_subsystem: PexSubsystem,
190     pex_environment_aware: PexSubsystem.EnvironmentAware,
191     subprocess_env_vars: SubprocessEnvironmentVars,
192     named_caches_dir: NamedCachesDirOption,
193 ) -> PexEnvironment:
194     return PexEnvironment(
195         path=pex_environment_aware.path,
196         interpreter_search_paths=python_bootstrap.interpreter_search_paths,
197         subprocess_environment_dict=subprocess_env_vars.vars,
198         named_caches_dir=named_caches_dir.val,
199         bootstrap_python=python_binary,
200         venv_use_symlinks=pex_subsystem.venv_use_symlinks,
201     )
202 
203 
204 @dataclass(frozen=True)
205 class CompletePexEnvironment:
206     _pex_environment: PexEnvironment
207     pex_root: PurePath
208     _working_directory: PurePath | None
209     append_only_caches: FrozenDict[str, str]
210 
211     @property
212     def interpreter_search_paths(self) -> tuple[str, ...]:
213         return self._pex_environment.interpreter_search_paths
214 
215     def create_argv(self, pex_filepath: str, *args: str) -> tuple[str, ...]:
216         pex_relpath = (
217             os.path.relpath(pex_filepath, self._working_directory)
218             if self._working_directory
219             else pex_filepath
220         )
221         return (self._pex_environment.bootstrap_python.path, pex_relpath, *args)
222 
223     def environment_dict(
224         self, *, python: PythonExecutable | PythonBuildStandaloneBinary | None = None
225     ) -> Mapping[str, str]:
226         """The environment to use for running anything with PEX.
227 
228         If the Process is run with a pre-selected Python interpreter, set `python_configured=True`
229         to avoid PEX from trying to find a new interpreter.
230         """
231         path = os.pathsep.join(self._pex_environment.path)
232         subprocess_env_dict = dict(self._pex_environment.subprocess_environment_dict)
233 
234         if "PATH" in self._pex_environment.subprocess_environment_dict:
235             path = os.pathsep.join([path, subprocess_env_dict.pop("PATH")])
236 
237         d = dict(
238             PATH=path,
239             PEX_IGNORE_RCFILES="true",
240             PEX_ROOT=(
241                 os.path.relpath(self.pex_root, self._working_directory)
242                 if self._working_directory
243                 else str(self.pex_root)
244             ),
245             **subprocess_env_dict,
246         )
247         if python:
248             d["PEX_PYTHON"] = python.path
249         else:
250             d["PEX_PYTHON_PATH"] = os.pathsep.join(self.interpreter_search_paths)
251         return d
252 
253 
254 def rules():
255     return [
256         *collect_rules(),
257         *subprocess_environment.rules(),
258         *system_binaries.rules(),
259     ]
260
```
--- 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/backend/python/util_rules/pex_environment.py b/src/python/pants/backend/python/util_rules/pex_environment.py
--- a/src/python/pants/backend/python/util_rules/pex_environment.py
+++ b/src/python/pants/backend/python/util_rules/pex_environment.py
@@ -89,8 +89,8 @@
 
             Note: Pants uses Pex internally in some ways that trigger some warnings at the moment,
             so enabling this may result in warnings not related to your code. See
-            <https://github.com/pantsbuild/pants/issues/20577> and
-            <https://github.com/pantsbuild/pants/issues/20586>.
+            [#20577](https://github.com/pantsbuild/pants/issues/20577) and
+            [#20586](https://github.com/pantsbuild/pants/issues/20586).
             """
         ),
     )

{"golden_diff": "diff --git a/src/python/pants/backend/python/util_rules/pex_environment.py b/src/python/pants/backend/python/util_rules/pex_environment.py\n--- a/src/python/pants/backend/python/util_rules/pex_environment.py\n+++ b/src/python/pants/backend/python/util_rules/pex_environment.py\n@@ -89,8 +89,8 @@\n \n             Note: Pants uses Pex internally in some ways that trigger some warnings at the moment,\n             so enabling this may result in warnings not related to your code. See\n-            <https://github.com/pantsbuild/pants/issues/20577> and\n-            <https://github.com/pantsbuild/pants/issues/20586>.\n+            [#20577](https://github.com/pantsbuild/pants/issues/20577) and\n+            [#20586](https://github.com/pantsbuild/pants/issues/20586).\n             \"\"\"\n         ),\n     )\n", "issue": "`[pex].emit_warnings` docs show `&#x3E;` literally instead of  `>`\n**Describe the bug**\r\n\r\nhttps://www.pantsbuild.org/2.20/reference/subsystems/pex#emit_warnings\r\n\r\n![image](https://github.com/pantsbuild/pants/assets/1203825/3c7f7152-3f56-4d74-9e49-fe5ad4d3e7ca)\r\n\r\n\r\n**Pants version**\r\n2.20\r\n\r\n**OS**\r\nN/A\r\n\r\n**Additional info**\r\n\n", "before_files": [{"content": "# Copyright 2019 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\nfrom dataclasses import dataclass\nfrom pathlib import PurePath\nfrom typing import Mapping\n\nfrom pants.core.subsystems.python_bootstrap import PythonBootstrap\nfrom pants.core.util_rules import subprocess_environment, system_binaries\nfrom pants.core.util_rules.adhoc_binaries import PythonBuildStandaloneBinary\nfrom pants.core.util_rules.subprocess_environment import SubprocessEnvironmentVars\nfrom pants.core.util_rules.system_binaries import BinaryPath\nfrom pants.engine.engine_aware import EngineAwareReturnType\nfrom pants.engine.rules import collect_rules, rule\nfrom pants.option.global_options import NamedCachesDirOption\nfrom pants.option.option_types import BoolOption, IntOption, StrListOption\nfrom pants.option.subsystem import Subsystem\nfrom pants.util.frozendict import FrozenDict\nfrom pants.util.logging import LogLevel\nfrom pants.util.memo import memoized_property\nfrom pants.util.ordered_set import OrderedSet\nfrom pants.util.strutil import softwrap\n\n\nclass PexSubsystem(Subsystem):\n    options_scope = \"pex\"\n    help = \"How Pants uses Pex to run Python subprocesses.\"\n\n    class EnvironmentAware(Subsystem.EnvironmentAware):\n        # TODO(#9760): We'll want to deprecate this in favor of a global option which allows for a\n        #  per-process override.\n\n        env_vars_used_by_options = (\"PATH\",)\n\n        _executable_search_paths = StrListOption(\n            default=[\"<PATH>\"],\n            help=softwrap(\n                \"\"\"\n                The PATH value that will be used by the PEX subprocess and any subprocesses it\n                spawns.\n\n                The special string `\"<PATH>\"` will expand to the contents of the PATH env var.\n                \"\"\"\n            ),\n            advanced=True,\n            metavar=\"<binary-paths>\",\n        )\n\n        @memoized_property\n        def path(self) -> tuple[str, ...]:\n            def iter_path_entries():\n                for entry in self._executable_search_paths:\n                    if entry == \"<PATH>\":\n                        path = self._options_env.get(\"PATH\")\n                        if path:\n                            yield from path.split(os.pathsep)\n                    else:\n                        yield entry\n\n            return tuple(OrderedSet(iter_path_entries()))\n\n    _verbosity = IntOption(\n        default=0,\n        help=\"Set the verbosity level of PEX logging, from 0 (no logging) up to 9 (max logging).\",\n        advanced=True,\n    )\n    venv_use_symlinks = BoolOption(\n        default=False,\n        help=softwrap(\n            \"\"\"\n            When possible, use venvs whose site-packages directories are populated with symlinks.\n\n            Enabling this can save space in the `--named-caches-dir` directory\n            and lead to slightly faster execution times for Pants Python goals. Some\n            distributions do not work with symlinked venvs though, so you may not be able to\n            enable this optimization as a result.\n            \"\"\"\n        ),\n        advanced=True,\n    )\n    emit_warnings = BoolOption(\n        default=False,\n        help=softwrap(\n            \"\"\"\n            If warnings from Pex should be logged by Pants to the console.\n\n            Note: Pants uses Pex internally in some ways that trigger some warnings at the moment,\n            so enabling this may result in warnings not related to your code. See\n            <https://github.com/pantsbuild/pants/issues/20577> and\n            <https://github.com/pantsbuild/pants/issues/20586>.\n            \"\"\"\n        ),\n    )\n\n    @property\n    def verbosity(self) -> int:\n        level = self._verbosity\n        if level < 0 or level > 9:\n            raise ValueError(\"verbosity level must be between 0 and 9\")\n        return level\n\n\n@dataclass(frozen=True)\nclass PythonExecutable(BinaryPath, EngineAwareReturnType):\n    \"\"\"The BinaryPath of a Python executable for user code, along with some extras.\"\"\"\n\n    append_only_caches: FrozenDict[str, str] = FrozenDict({})\n\n    def __init__(\n        self,\n        path: str,\n        fingerprint: str | None = None,\n        append_only_caches: Mapping[str, str] = FrozenDict({}),\n    ) -> None:\n        object.__setattr__(self, \"append_only_caches\", FrozenDict(append_only_caches))\n        super().__init__(path, fingerprint)\n        self.__post_init__()\n\n    def __post_init__(self) -> None:\n        if not PurePath(self.path).is_absolute():\n            raise ValueError(\n                softwrap(\n                    f\"\"\"\n                    PythonExecutable expects the path to be absolute. Tools like Pex internalize the\n                    absolute path to Python (since `sys.executable` is expected to be absolute).\n\n                    In order to ensure the cache key for Python process is \"correct\" (especially in\n                    remote cache/execution situations) we require the Python path is absolute.\n\n                    Got: {self.path}\n                    \"\"\"\n                )\n            )\n\n    def message(self) -> str:\n        return f\"Selected {self.path} to run PEXes with.\"\n\n\n@dataclass(frozen=True)\nclass PexEnvironment:\n    path: tuple[str, ...]\n    interpreter_search_paths: tuple[str, ...]\n    subprocess_environment_dict: FrozenDict[str, str]\n    named_caches_dir: PurePath\n    bootstrap_python: PythonBuildStandaloneBinary\n    venv_use_symlinks: bool = False\n\n    _PEX_ROOT_DIRNAME = \"pex_root\"\n\n    def in_sandbox(self, *, working_directory: str | None) -> CompletePexEnvironment:\n        pex_root = PurePath(\".cache\") / self._PEX_ROOT_DIRNAME\n        return CompletePexEnvironment(\n            _pex_environment=self,\n            pex_root=pex_root,\n            _working_directory=PurePath(working_directory) if working_directory else None,\n            append_only_caches=FrozenDict(\n                **{self._PEX_ROOT_DIRNAME: str(pex_root)},\n                **self.bootstrap_python.APPEND_ONLY_CACHES,\n            ),\n        )\n\n    def in_workspace(self) -> CompletePexEnvironment:\n        # N.B.: When running in the workspace the engine doesn't offer an append_only_caches\n        # service to setup a symlink to our named cache for us. As such, we point the PEX_ROOT\n        # directly at the underlying append only cache in that case to re-use results there and\n        # to keep the workspace from being dirtied by the creation of a new Pex cache rooted\n        # there.\n        pex_root = self.named_caches_dir / self._PEX_ROOT_DIRNAME\n        return CompletePexEnvironment(\n            _pex_environment=self,\n            pex_root=pex_root,\n            _working_directory=None,\n            append_only_caches=self.bootstrap_python.APPEND_ONLY_CACHES,\n        )\n\n    def venv_site_packages_copies_option(self, use_copies: bool) -> str:\n        if self.venv_use_symlinks and not use_copies:\n            return \"--no-venv-site-packages-copies\"\n        return \"--venv-site-packages-copies\"\n\n\n@rule(desc=\"Prepare environment for running PEXes\", level=LogLevel.DEBUG)\nasync def find_pex_python(\n    python_bootstrap: PythonBootstrap,\n    python_binary: PythonBuildStandaloneBinary,\n    pex_subsystem: PexSubsystem,\n    pex_environment_aware: PexSubsystem.EnvironmentAware,\n    subprocess_env_vars: SubprocessEnvironmentVars,\n    named_caches_dir: NamedCachesDirOption,\n) -> PexEnvironment:\n    return PexEnvironment(\n        path=pex_environment_aware.path,\n        interpreter_search_paths=python_bootstrap.interpreter_search_paths,\n        subprocess_environment_dict=subprocess_env_vars.vars,\n        named_caches_dir=named_caches_dir.val,\n        bootstrap_python=python_binary,\n        venv_use_symlinks=pex_subsystem.venv_use_symlinks,\n    )\n\n\n@dataclass(frozen=True)\nclass CompletePexEnvironment:\n    _pex_environment: PexEnvironment\n    pex_root: PurePath\n    _working_directory: PurePath | None\n    append_only_caches: FrozenDict[str, str]\n\n    @property\n    def interpreter_search_paths(self) -> tuple[str, ...]:\n        return self._pex_environment.interpreter_search_paths\n\n    def create_argv(self, pex_filepath: str, *args: str) -> tuple[str, ...]:\n        pex_relpath = (\n            os.path.relpath(pex_filepath, self._working_directory)\n            if self._working_directory\n            else pex_filepath\n        )\n        return (self._pex_environment.bootstrap_python.path, pex_relpath, *args)\n\n    def environment_dict(\n        self, *, python: PythonExecutable | PythonBuildStandaloneBinary | None = None\n    ) -> Mapping[str, str]:\n        \"\"\"The environment to use for running anything with PEX.\n\n        If the Process is run with a pre-selected Python interpreter, set `python_configured=True`\n        to avoid PEX from trying to find a new interpreter.\n        \"\"\"\n        path = os.pathsep.join(self._pex_environment.path)\n        subprocess_env_dict = dict(self._pex_environment.subprocess_environment_dict)\n\n        if \"PATH\" in self._pex_environment.subprocess_environment_dict:\n            path = os.pathsep.join([path, subprocess_env_dict.pop(\"PATH\")])\n\n        d = dict(\n            PATH=path,\n            PEX_IGNORE_RCFILES=\"true\",\n            PEX_ROOT=(\n                os.path.relpath(self.pex_root, self._working_directory)\n                if self._working_directory\n                else str(self.pex_root)\n            ),\n            **subprocess_env_dict,\n        )\n        if python:\n            d[\"PEX_PYTHON\"] = python.path\n        else:\n            d[\"PEX_PYTHON_PATH\"] = os.pathsep.join(self.interpreter_search_paths)\n        return d\n\n\ndef rules():\n    return [\n        *collect_rules(),\n        *subprocess_environment.rules(),\n        *system_binaries.rules(),\n    ]\n", "path": "src/python/pants/backend/python/util_rules/pex_environment.py"}], "after_files": [{"content": "# Copyright 2019 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\nfrom dataclasses import dataclass\nfrom pathlib import PurePath\nfrom typing import Mapping\n\nfrom pants.core.subsystems.python_bootstrap import PythonBootstrap\nfrom pants.core.util_rules import subprocess_environment, system_binaries\nfrom pants.core.util_rules.adhoc_binaries import PythonBuildStandaloneBinary\nfrom pants.core.util_rules.subprocess_environment import SubprocessEnvironmentVars\nfrom pants.core.util_rules.system_binaries import BinaryPath\nfrom pants.engine.engine_aware import EngineAwareReturnType\nfrom pants.engine.rules import collect_rules, rule\nfrom pants.option.global_options import NamedCachesDirOption\nfrom pants.option.option_types import BoolOption, IntOption, StrListOption\nfrom pants.option.subsystem import Subsystem\nfrom pants.util.frozendict import FrozenDict\nfrom pants.util.logging import LogLevel\nfrom pants.util.memo import memoized_property\nfrom pants.util.ordered_set import OrderedSet\nfrom pants.util.strutil import softwrap\n\n\nclass PexSubsystem(Subsystem):\n    options_scope = \"pex\"\n    help = \"How Pants uses Pex to run Python subprocesses.\"\n\n    class EnvironmentAware(Subsystem.EnvironmentAware):\n        # TODO(#9760): We'll want to deprecate this in favor of a global option which allows for a\n        #  per-process override.\n\n        env_vars_used_by_options = (\"PATH\",)\n\n        _executable_search_paths = StrListOption(\n            default=[\"<PATH>\"],\n            help=softwrap(\n                \"\"\"\n                The PATH value that will be used by the PEX subprocess and any subprocesses it\n                spawns.\n\n                The special string `\"<PATH>\"` will expand to the contents of the PATH env var.\n                \"\"\"\n            ),\n            advanced=True,\n            metavar=\"<binary-paths>\",\n        )\n\n        @memoized_property\n        def path(self) -> tuple[str, ...]:\n            def iter_path_entries():\n                for entry in self._executable_search_paths:\n                    if entry == \"<PATH>\":\n                        path = self._options_env.get(\"PATH\")\n                        if path:\n                            yield from path.split(os.pathsep)\n                    else:\n                        yield entry\n\n            return tuple(OrderedSet(iter_path_entries()))\n\n    _verbosity = IntOption(\n        default=0,\n        help=\"Set the verbosity level of PEX logging, from 0 (no logging) up to 9 (max logging).\",\n        advanced=True,\n    )\n    venv_use_symlinks = BoolOption(\n        default=False,\n        help=softwrap(\n            \"\"\"\n            When possible, use venvs whose site-packages directories are populated with symlinks.\n\n            Enabling this can save space in the `--named-caches-dir` directory\n            and lead to slightly faster execution times for Pants Python goals. Some\n            distributions do not work with symlinked venvs though, so you may not be able to\n            enable this optimization as a result.\n            \"\"\"\n        ),\n        advanced=True,\n    )\n    emit_warnings = BoolOption(\n        default=False,\n        help=softwrap(\n            \"\"\"\n            If warnings from Pex should be logged by Pants to the console.\n\n            Note: Pants uses Pex internally in some ways that trigger some warnings at the moment,\n            so enabling this may result in warnings not related to your code. See\n            [#20577](https://github.com/pantsbuild/pants/issues/20577) and\n            [#20586](https://github.com/pantsbuild/pants/issues/20586).\n            \"\"\"\n        ),\n    )\n\n    @property\n    def verbosity(self) -> int:\n        level = self._verbosity\n        if level < 0 or level > 9:\n            raise ValueError(\"verbosity level must be between 0 and 9\")\n        return level\n\n\n@dataclass(frozen=True)\nclass PythonExecutable(BinaryPath, EngineAwareReturnType):\n    \"\"\"The BinaryPath of a Python executable for user code, along with some extras.\"\"\"\n\n    append_only_caches: FrozenDict[str, str] = FrozenDict({})\n\n    def __init__(\n        self,\n        path: str,\n        fingerprint: str | None = None,\n        append_only_caches: Mapping[str, str] = FrozenDict({}),\n    ) -> None:\n        object.__setattr__(self, \"append_only_caches\", FrozenDict(append_only_caches))\n        super().__init__(path, fingerprint)\n        self.__post_init__()\n\n    def __post_init__(self) -> None:\n        if not PurePath(self.path).is_absolute():\n            raise ValueError(\n                softwrap(\n                    f\"\"\"\n                    PythonExecutable expects the path to be absolute. Tools like Pex internalize the\n                    absolute path to Python (since `sys.executable` is expected to be absolute).\n\n                    In order to ensure the cache key for Python process is \"correct\" (especially in\n                    remote cache/execution situations) we require the Python path is absolute.\n\n                    Got: {self.path}\n                    \"\"\"\n                )\n            )\n\n    def message(self) -> str:\n        return f\"Selected {self.path} to run PEXes with.\"\n\n\n@dataclass(frozen=True)\nclass PexEnvironment:\n    path: tuple[str, ...]\n    interpreter_search_paths: tuple[str, ...]\n    subprocess_environment_dict: FrozenDict[str, str]\n    named_caches_dir: PurePath\n    bootstrap_python: PythonBuildStandaloneBinary\n    venv_use_symlinks: bool = False\n\n    _PEX_ROOT_DIRNAME = \"pex_root\"\n\n    def in_sandbox(self, *, working_directory: str | None) -> CompletePexEnvironment:\n        pex_root = PurePath(\".cache\") / self._PEX_ROOT_DIRNAME\n        return CompletePexEnvironment(\n            _pex_environment=self,\n            pex_root=pex_root,\n            _working_directory=PurePath(working_directory) if working_directory else None,\n            append_only_caches=FrozenDict(\n                **{self._PEX_ROOT_DIRNAME: str(pex_root)},\n                **self.bootstrap_python.APPEND_ONLY_CACHES,\n            ),\n        )\n\n    def in_workspace(self) -> CompletePexEnvironment:\n        # N.B.: When running in the workspace the engine doesn't offer an append_only_caches\n        # service to setup a symlink to our named cache for us. As such, we point the PEX_ROOT\n        # directly at the underlying append only cache in that case to re-use results there and\n        # to keep the workspace from being dirtied by the creation of a new Pex cache rooted\n        # there.\n        pex_root = self.named_caches_dir / self._PEX_ROOT_DIRNAME\n        return CompletePexEnvironment(\n            _pex_environment=self,\n            pex_root=pex_root,\n            _working_directory=None,\n            append_only_caches=self.bootstrap_python.APPEND_ONLY_CACHES,\n        )\n\n    def venv_site_packages_copies_option(self, use_copies: bool) -> str:\n        if self.venv_use_symlinks and not use_copies:\n            return \"--no-venv-site-packages-copies\"\n        return \"--venv-site-packages-copies\"\n\n\n@rule(desc=\"Prepare environment for running PEXes\", level=LogLevel.DEBUG)\nasync def find_pex_python(\n    python_bootstrap: PythonBootstrap,\n    python_binary: PythonBuildStandaloneBinary,\n    pex_subsystem: PexSubsystem,\n    pex_environment_aware: PexSubsystem.EnvironmentAware,\n    subprocess_env_vars: SubprocessEnvironmentVars,\n    named_caches_dir: NamedCachesDirOption,\n) -> PexEnvironment:\n    return PexEnvironment(\n        path=pex_environment_aware.path,\n        interpreter_search_paths=python_bootstrap.interpreter_search_paths,\n        subprocess_environment_dict=subprocess_env_vars.vars,\n        named_caches_dir=named_caches_dir.val,\n        bootstrap_python=python_binary,\n        venv_use_symlinks=pex_subsystem.venv_use_symlinks,\n    )\n\n\n@dataclass(frozen=True)\nclass CompletePexEnvironment:\n    _pex_environment: PexEnvironment\n    pex_root: PurePath\n    _working_directory: PurePath | None\n    append_only_caches: FrozenDict[str, str]\n\n    @property\n    def interpreter_search_paths(self) -> tuple[str, ...]:\n        return self._pex_environment.interpreter_search_paths\n\n    def create_argv(self, pex_filepath: str, *args: str) -> tuple[str, ...]:\n        pex_relpath = (\n            os.path.relpath(pex_filepath, self._working_directory)\n            if self._working_directory\n            else pex_filepath\n        )\n        return (self._pex_environment.bootstrap_python.path, pex_relpath, *args)\n\n    def environment_dict(\n        self, *, python: PythonExecutable | PythonBuildStandaloneBinary | None = None\n    ) -> Mapping[str, str]:\n        \"\"\"The environment to use for running anything with PEX.\n\n        If the Process is run with a pre-selected Python interpreter, set `python_configured=True`\n        to avoid PEX from trying to find a new interpreter.\n        \"\"\"\n        path = os.pathsep.join(self._pex_environment.path)\n        subprocess_env_dict = dict(self._pex_environment.subprocess_environment_dict)\n\n        if \"PATH\" in self._pex_environment.subprocess_environment_dict:\n            path = os.pathsep.join([path, subprocess_env_dict.pop(\"PATH\")])\n\n        d = dict(\n            PATH=path,\n            PEX_IGNORE_RCFILES=\"true\",\n            PEX_ROOT=(\n                os.path.relpath(self.pex_root, self._working_directory)\n                if self._working_directory\n                else str(self.pex_root)\n            ),\n            **subprocess_env_dict,\n        )\n        if python:\n            d[\"PEX_PYTHON\"] = python.path\n        else:\n            d[\"PEX_PYTHON_PATH\"] = os.pathsep.join(self.interpreter_search_paths)\n        return d\n\n\ndef rules():\n    return [\n        *collect_rules(),\n        *subprocess_environment.rules(),\n        *system_binaries.rules(),\n    ]\n", "path": "src/python/pants/backend/python/util_rules/pex_environment.py"}]}