# Buggy code
def message_about_scripts_not_on_PATH(scripts):
    # type: (List[str]) -> Optional[str]
    """Determine if any scripts are not on PATH and format a warning.

    Returns a warning message if one or more scripts are not on PATH,
    otherwise None.
    """
    if not scripts:
        return None

    # Group scripts by the path they were installed in
    grouped_by_dir = collections.defaultdict(set)  # type: Dict[str, set]
    for destfile in scripts:
        parent_dir = os.path.dirname(destfile)
        script_name = os.path.basename(destfile)
        grouped_by_dir[parent_dir].add(script_name)

    # We don't want to warn for directories that are on PATH.
    not_warn_dirs = [
        os.path.normcase(i).rstrip(os.sep) for i in os.environ["PATH"].split(os.pathsep)
    ]
    # If an executable sits with sys.executable, we don't warn for it.
    #     This covers the case of venv invocations without activating the venv.
    not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable)))
    warn_for = {
        parent_dir: scripts
        for parent_dir, scripts in grouped_by_dir.items()
        if os.path.normcase(parent_dir) not in not_warn_dirs
    }
    if not warn_for:
        return None

    # Format a message
    msg_lines = []
    for parent_dir, scripts in warn_for.items():
        scripts = sorted(scripts)
        if len(scripts) == 1:
            start_text = "script {} is".format(scripts[0])
        else:
            start_text = "scripts {} are".format(
                ", ".join(scripts[:-1]) + " and " + scripts[-1]
            )

        msg_lines.append(
            "The {} installed in '{}' which is not on PATH.".format(
                start_text, parent_dir
            )
        )

    last_line_fmt = (
        "Consider adding {} to PATH or, if you prefer "
        "to suppress this warning, use --no-warn-script-location."
    )
    if len(msg_lines) == 1:
        msg_lines.append(last_line_fmt.format("this directory"))
    else:
        msg_lines.append(last_line_fmt.format("these directories"))

    # Returns the formatted multiline message
    return "\n".join(msg_lines)


# Traceback (KeyError)
(pip-path-error)oj:~$ unset PATH
(pip-path-error)oj:~$ /home/oj/virtualenv/pip-path-error/bin/pip install --upgrade django==1.11
Looking in indexes: https://oliver.jeeves:<password>@<internal_pypi_server>/repository/pypi/simple
Collecting django==1.11
Using cached https://<internal_pypi_server>/repository/pypi/packages/47/a6/078ebcbd49b19e22fd560a2348cfc5cec9e5dcfe3c4fad8e64c9865135bb/Django-1.11-py2.py3-none-any.whl
Collecting pytz (from django==1.11)
Downloading https://<internal_pypi_server>/repository/pypi/packages/30/4e/27c34b62430286c6d59177a0842ed90dc789ce5d1ed740887653b898779a/pytz-2018.5-py2.py3-none-any.whl (510kB)
100% |████████████████████████████████| 512kB 18.6MB/s
Installing collected packages: pytz, django
Found existing installation: Django 1.9
Uninstalling Django-1.9:
Successfully uninstalled Django-1.9
Rolling back uninstall of Django
Exception:
Traceback (most recent call last):
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/basecommand.py", line 228, in main
status = self.run(options, args)
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/commands/install.py", line 335, in run
use_user_site=options.use_user_site,
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/req/__init__.py", line 49, in install_given_reqs
**kwargs
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/req/req_install.py", line 748, in install
use_user_site=use_user_site, pycompile=pycompile,
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/req/req_install.py", line 961, in move_wheel_files
warn_script_location=warn_script_location,
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/wheel.py", line 466, in move_wheel_files
msg = message_about_scripts_not_on_PATH(generated_console_scripts)
File "/home/oj/virtualenv/pip-path-error/local/lib/python2.7/site-packages/pip/_internal/wheel.py", line 167, in message_about_scripts_not_on_PATH
os.path.normcase(i) for i in os.environ["PATH"].split(os.pathsep)
File "/home/oj/virtualenv/pip-path-error/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'PATH'

# Fixed code
def message_about_scripts_not_on_PATH(scripts):
    # type: (List[str]) -> Optional[str]
    """Determine if any scripts are not on PATH and format a warning.

    Returns a warning message if one or more scripts are not on PATH,
    otherwise None.
    """
    if not scripts:
        return None

    # Group scripts by the path they were installed in
    grouped_by_dir = collections.defaultdict(set)  # type: Dict[str, set]
    for destfile in scripts:
        parent_dir = os.path.dirname(destfile)
        script_name = os.path.basename(destfile)
        grouped_by_dir[parent_dir].add(script_name)

    # We don't want to warn for directories that are on PATH.
    not_warn_dirs = [
        os.path.normcase(i).rstrip(os.sep)
        for i in os.environ.get("PATH", "").split(os.pathsep)
    ]
    # If an executable sits with sys.executable, we don't warn for it.
    #     This covers the case of venv invocations without activating the venv.
    not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable)))
    warn_for = {
        parent_dir: scripts
        for parent_dir, scripts in grouped_by_dir.items()
        if os.path.normcase(parent_dir) not in not_warn_dirs
    }
    if not warn_for:
        return None

    # Format a message
    msg_lines = []
    for parent_dir, scripts in warn_for.items():
        scripts = sorted(scripts)
        if len(scripts) == 1:
            start_text = "script {} is".format(scripts[0])
        else:
            start_text = "scripts {} are".format(
                ", ".join(scripts[:-1]) + " and " + scripts[-1]
            )

        msg_lines.append(
            "The {} installed in '{}' which is not on PATH.".format(
                start_text, parent_dir
            )
        )

    last_line_fmt = (
        "Consider adding {} to PATH or, if you prefer "
        "to suppress this warning, use --no-warn-script-location."
    )
    if len(msg_lines) == 1:
        msg_lines.append(last_line_fmt.format("this directory"))
    else:
        msg_lines.append(last_line_fmt.format("these directories"))

    # Returns the formatted multiline message
    return "\n".join(msg_lines)