# Buggy code
def _spawn_from_binary_external(cls, binary):
    def create_interpreter(stdout, check_binary=False):
        identity = stdout.decode("utf-8").strip()
        if not identity:
            raise cls.IdentificationError(
                "Could not establish identity of {}.".format(binary)
            )
        interpreter = cls(PythonIdentity.decode(identity))
        # We should not need to check this since binary == interpreter.binary should always be
        # true, but historically this could be untrue as noted in `PythonIdentity.get`.
        if check_binary and not os.path.exists(interpreter.binary):
            raise cls.InterpreterNotFound(
                "Cached interpreter for {} reports a binary of {}, which could not be found".format(
                    binary, interpreter.binary
                )
            )
        return interpreter

    # Part of the PythonInterpreter data are environment markers that depend on the current OS
    # release. That data can change when the OS is upgraded but (some of) the installed interpreters
    # remain the same. As such, include the OS in the hash structure for cached interpreters.
    os_digest = hashlib.sha1()
    for os_identifier in platform.release(), platform.version():
        os_digest.update(os_identifier.encode("utf-8"))
    os_hash = os_digest.hexdigest()

    interpreter_cache_dir = os.path.join(ENV.PEX_ROOT, "interpreters")
    os_cache_dir = os.path.join(interpreter_cache_dir, os_hash)
    if os.path.isdir(interpreter_cache_dir) and not os.path.isdir(os_cache_dir):
        with TRACER.timed("GCing interpreter cache from prior OS version"):
            safe_rmtree(interpreter_cache_dir)

    interpreter_hash = CacheHelper.hash(binary)

    # Some distributions include more than one copy of the same interpreter via a hard link (e.g.:
    # python3.7 is a hardlink to python3.7m). To ensure a deterministic INTERP-INFO file we must
    # emit a separate INTERP-INFO for each link since INTERP-INFO contains the interpreter path and
    # would otherwise be unstable.
    #
    # See cls._REGEXEN for a related affordance.
    path_id = binary.replace(os.sep, ".").lstrip(".")

    cache_dir = os.path.join(os_cache_dir, interpreter_hash, path_id)
    cache_file = os.path.join(cache_dir, cls.INTERP_INFO_FILE)
    if os.path.isfile(cache_file):
        try:
            with open(cache_file, "rb") as fp:
                return SpawnedJob.completed(
                    create_interpreter(fp.read(), check_binary=True)
                )
        except (IOError, OSError, cls.Error, PythonIdentity.Error):
            safe_rmtree(cache_dir)
            return cls._spawn_from_binary_external(binary)
    else:
        pythonpath = third_party.expose(["pex"])
        cmd, env = cls._create_isolated_cmd(
            binary,
            args=[
                "-c",
                dedent(
                    """\
                        import os
                        import sys

                        from pex.common import atomic_directory, safe_open
                        from pex.interpreter import PythonIdentity


                        encoded_identity = PythonIdentity.get(binary={binary!r}).encode()
                        sys.stdout.write(encoded_identity)
                        with atomic_directory({cache_dir!r}) as cache_dir:
                            if cache_dir:
                                with safe_open(os.path.join(cache_dir, {info_file!r}), 'w') as fp:
                                    fp.write(encoded_identity)
                        """.format(
                        binary=binary,
                        cache_dir=cache_dir,
                        info_file=cls.INTERP_INFO_FILE,
                    )
                ),
            ],
            pythonpath=pythonpath,
        )
        process = Executor.open_process(
            cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
        job = Job(command=cmd, process=process)
        return SpawnedJob.stdout(job, result_func=create_interpreter)


# Traceback (pants.engine.internals.scheduler.ExecutionError)
23:06:05.36 [INFO] Starting: Resolving 3rdparty/python/constraints.txt
23:06:05.38 [WARN] /home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/base/exception_sink.py:313: DeprecationWarning: PY_SSIZE_T_CLEAN will be required for '#' formats
process_title=setproctitle.getproctitle(),
23:06:05.38 [ERROR] 1 Exception encountered:
Engine traceback:
in select
in `typecheck` goal
in Typecheck using MyPy
in pants.backend.python.typecheck.mypy.rules.mypy_typecheck_partition
in pants.backend.python.util_rules.pex.create_pex
in pants.engine.process.fallible_to_exec_result_or_raise
Traceback (most recent call last):
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/engine/process.py", line 241, in fallible_to_exec_result_or_raise
raise ProcessExecutionFailure(
pants.engine.process.ProcessExecutionFailure: Process 'Building mypy.pex with 1 requirement: mypy==0.782' failed with exit code 1.
stdout:
stderr:
Failed to spawn a job for DistributionTarget(interpreter=PythonInterpreter('/usr/local/bin/python3.8', PythonIdentity('/usr/local/bin/python3.8', 'cp38', 'cp38', 'manylinux2014_x86_64', (3, 8, 5)))): [Errno 2] No such file or directory: '/home/toolchain/.pex/unzipped_pexes/49b4b32295a60a0a4dfc0659c3a44f93560c4a81/.deps/pex-2.1.16-py2.py3-none-any.whl/pex/__pycache__/variables.cpython-37.pyc.139923989690656'
Traceback (most recent call last):
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/bin/local_pants_runner.py", line 256, in run
engine_result = self._run_v2()
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/bin/local_pants_runner.py", line 168, in _run_v2
return self._maybe_run_v2_body(goals, poll=False)
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/bin/local_pants_runner.py", line 185, in _maybe_run_v2_body
return self.graph_session.run_goal_rules(
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/init/engine_initializer.py", line 125, in run_goal_rules
exit_code = self.scheduler_session.run_goal_rule(
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/engine/internals/scheduler.py", line 568, in run_goal_rule
self._raise_on_error([t for _, t in throws])
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/engine/internals/scheduler.py", line 527, in _raise_on_error
raise ExecutionError(
pants.engine.internals.scheduler.ExecutionError: 1 Exception encountered:
Engine traceback:
in select
in `typecheck` goal
in Typecheck using MyPy
in pants.backend.python.typecheck.mypy.rules.mypy_typecheck_partition
in pants.backend.python.util_rules.pex.create_pex
in pants.engine.process.fallible_to_exec_result_or_raise
Traceback (most recent call last):
File "/home/toolchain/.cache/pants/setup/bootstrap-Linux-x86_64/2.0.0b2_py38/lib/python3.8/site-packages/pants/engine/process.py", line 241, in fallible_to_exec_result_or_raise
raise ProcessExecutionFailure(
pants.engine.process.ProcessExecutionFailure: Process 'Building mypy.pex with 1 requirement: mypy==0.782' failed with exit code 1.
stdout:
stderr:
Failed to spawn a job for DistributionTarget(interpreter=PythonInterpreter('/usr/local/bin/python3.8', PythonIdentity('/usr/local/bin/python3.8', 'cp38', 'cp38', 'manylinux2014_x86_64', (3, 8, 5)))): [Errno 2] No such file or directory: '/home/toolchain/.pex/unzipped_pexes/49b4b32295a60a0a4dfc0659c3a44f93560c4a81/.deps/pex-2.1.16-py2.py3-none-any.whl/pex/__pycache__/variables.cpython-37.pyc.139923989690656'

# Fixed code
def _spawn_from_binary_external(cls, binary):
    def create_interpreter(stdout, check_binary=False):
        identity = stdout.decode("utf-8").strip()
        if not identity:
            raise cls.IdentificationError(
                "Could not establish identity of {}.".format(binary)
            )
        interpreter = cls(PythonIdentity.decode(identity))
        # We should not need to check this since binary == interpreter.binary should always be
        # true, but historically this could be untrue as noted in `PythonIdentity.get`.
        if check_binary and not os.path.exists(interpreter.binary):
            raise cls.InterpreterNotFound(
                "Cached interpreter for {} reports a binary of {}, which could not be found".format(
                    binary, interpreter.binary
                )
            )
        return interpreter

    # Part of the PythonInterpreter data are environment markers that depend on the current OS
    # release. That data can change when the OS is upgraded but (some of) the installed interpreters
    # remain the same. As such, include the OS in the hash structure for cached interpreters.
    os_digest = hashlib.sha1()
    for os_identifier in platform.release(), platform.version():
        os_digest.update(os_identifier.encode("utf-8"))
    os_hash = os_digest.hexdigest()

    interpreter_cache_dir = os.path.join(ENV.PEX_ROOT, "interpreters")
    os_cache_dir = os.path.join(interpreter_cache_dir, os_hash)
    if os.path.isdir(interpreter_cache_dir) and not os.path.isdir(os_cache_dir):
        with TRACER.timed("GCing interpreter cache from prior OS version"):
            safe_rmtree(interpreter_cache_dir)

    interpreter_hash = CacheHelper.hash(binary)

    # Some distributions include more than one copy of the same interpreter via a hard link (e.g.:
    # python3.7 is a hardlink to python3.7m). To ensure a deterministic INTERP-INFO file we must
    # emit a separate INTERP-INFO for each link since INTERP-INFO contains the interpreter path and
    # would otherwise be unstable.
    #
    # See cls._REGEXEN for a related affordance.
    path_id = binary.replace(os.sep, ".").lstrip(".")

    cache_dir = os.path.join(os_cache_dir, interpreter_hash, path_id)
    cache_file = os.path.join(cache_dir, cls.INTERP_INFO_FILE)
    if os.path.isfile(cache_file):
        try:
            with open(cache_file, "rb") as fp:
                return SpawnedJob.completed(
                    create_interpreter(fp.read(), check_binary=True)
                )
        except (IOError, OSError, cls.Error, PythonIdentity.Error):
            safe_rmtree(cache_dir)
            return cls._spawn_from_binary_external(binary)
    else:
        pythonpath = third_party.expose(["pex"])
        cmd, env = cls._create_isolated_cmd(
            binary,
            args=[
                "-c",
                dedent(
                    """\
                        import os
                        import sys

                        from pex.common import atomic_directory, safe_open
                        from pex.interpreter import PythonIdentity


                        encoded_identity = PythonIdentity.get(binary={binary!r}).encode()
                        sys.stdout.write(encoded_identity)
                        with atomic_directory({cache_dir!r}, exclusive=False) as cache_dir:
                            if cache_dir:
                                with safe_open(os.path.join(cache_dir, {info_file!r}), 'w') as fp:
                                    fp.write(encoded_identity)
                        """.format(
                        binary=binary,
                        cache_dir=cache_dir,
                        info_file=cls.INTERP_INFO_FILE,
                    )
                ),
            ],
            pythonpath=pythonpath,
        )
        process = Executor.open_process(
            cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
        job = Job(command=cmd, process=process)
        return SpawnedJob.stdout(job, result_func=create_interpreter)