# Buggy code
def foreign_shell_data(
    shell,
    interactive=True,
    login=False,
    envcmd=None,
    aliascmd=None,
    extra_args=(),
    currenv=None,
    safe=True,
    prevcmd="",
    postcmd="",
    funcscmd=None,
    sourcer=None,
    use_tmpfile=False,
    tmpfile_ext=None,
    runcmd=None,
    seterrprevcmd=None,
    seterrpostcmd=None,
):
    """Extracts data from a foreign (non-xonsh) shells. Currently this gets
    the environment, aliases, and functions but may be extended in the future.

    Parameters
    ----------
    shell : str
        The name of the shell, such as 'bash' or '/bin/sh'.
    interactive : bool, optional
        Whether the shell should be run in interactive mode.
    login : bool, optional
        Whether the shell should be a login shell.
    envcmd : str or None, optional
        The command to generate environment output with.
    aliascmd : str or None, optional
        The command to generate alias output with.
    extra_args : tuple of str, optional
        Addtional command line options to pass into the shell.
    currenv : tuple of items or None, optional
        Manual override for the current environment.
    safe : bool, optional
        Flag for whether or not to safely handle exceptions and other errors.
    prevcmd : str, optional
        A command to run in the shell before anything else, useful for
        sourcing and other commands that may require environment recovery.
    postcmd : str, optional
        A command to run after everything else, useful for cleaning up any
        damage that the prevcmd may have caused.
    funcscmd : str or None, optional
        This is a command or script that can be used to determine the names
        and locations of any functions that are native to the foreign shell.
        This command should print *only* a JSON object that maps
        function names to the filenames where the functions are defined.
        If this is None, then a default script will attempted to be looked
        up based on the shell name. Callable wrappers for these functions
        will be returned in the aliases dictionary.
    sourcer : str or None, optional
        How to source a foreign shell file for purposes of calling functions
        in that shell. If this is None, a default value will attempt to be
        looked up based on the shell name.
    use_tmpfile : bool, optional
        This specifies if the commands are written to a tmp file or just
        parsed directly to the shell
    tmpfile_ext : str or None, optional
        If tmpfile is True this sets specifies the extension used.
    runcmd : str or None, optional
        Command line switches to use when running the script, such as
        -c for Bash and /C for cmd.exe.
    seterrprevcmd : str or None, optional
        Command that enables exit-on-error for the shell that is run at the
        start of the script. For example, this is "set -e" in Bash. To disable
        exit-on-error behavior, simply pass in an empty string.
    seterrpostcmd : str or None, optional
        Command that enables exit-on-error for the shell that is run at the end
        of the script. For example, this is "if errorlevel 1 exit 1" in
        cmd.exe. To disable exit-on-error behavior, simply pass in an
        empty string.

    Returns
    -------
    env : dict
        Dictionary of shell's environment
    aliases : dict
        Dictionary of shell's alaiases, this includes foreign function
        wrappers.
    """
    cmd = [shell]
    cmd.extend(extra_args)  # needs to come here for GNU long options
    if interactive:
        cmd.append("-i")
    if login:
        cmd.append("-l")
    shkey = CANON_SHELL_NAMES[shell]
    envcmd = DEFAULT_ENVCMDS.get(shkey, "env") if envcmd is None else envcmd
    aliascmd = DEFAULT_ALIASCMDS.get(shkey, "alias") if aliascmd is None else aliascmd
    funcscmd = DEFAULT_FUNCSCMDS.get(shkey, "echo {}") if funcscmd is None else funcscmd
    tmpfile_ext = (
        DEFAULT_TMPFILE_EXT.get(shkey, "sh") if tmpfile_ext is None else tmpfile_ext
    )
    runcmd = DEFAULT_RUNCMD.get(shkey, "-c") if runcmd is None else runcmd
    seterrprevcmd = (
        DEFAULT_SETERRPREVCMD.get(shkey, "") if seterrprevcmd is None else seterrprevcmd
    )
    seterrpostcmd = (
        DEFAULT_SETERRPOSTCMD.get(shkey, "") if seterrpostcmd is None else seterrpostcmd
    )
    command = COMMAND.format(
        envcmd=envcmd,
        aliascmd=aliascmd,
        prevcmd=prevcmd,
        postcmd=postcmd,
        funcscmd=funcscmd,
        seterrprevcmd=seterrprevcmd,
        seterrpostcmd=seterrpostcmd,
    ).strip()

    cmd.append(runcmd)

    if not use_tmpfile:
        cmd.append(command)
    else:
        tmpfile = NamedTemporaryFile(suffix=tmpfile_ext, delete=False)
        tmpfile.write(command.encode("utf8"))
        tmpfile.close()
        cmd.append(tmpfile.name)

    if currenv is None and hasattr(builtins, "__xonsh_env__"):
        currenv = builtins.__xonsh_env__.detype()
    elif currenv is not None:
        currenv = dict(currenv)
    try:
        s = subprocess.check_output(
            cmd,
            stderr=subprocess.PIPE,
            env=currenv,
            # start new session to avoid hangs
            start_new_session=True,
            universal_newlines=True,
        )
    except (subprocess.CalledProcessError, FileNotFoundError):
        if not safe:
            raise
        return None, None
    finally:
        if use_tmpfile:
            os.remove(tmpfile.name)
    env = parse_env(s)
    aliases = parse_aliases(s)
    funcs = parse_funcs(s, shell=shell, sourcer=sourcer)
    aliases.update(funcs)
    return env, aliases


# Traceback (AttributeError)
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
self.run()
File "/usr/lib/python3.4/site-packages/xonsh/readline_shell.py", line 281, in run
RL_LIB.history_set_pos(i)
File "/usr/lib/python3.4/ctypes/__init__.py", line 364, in __getattr__
func = self.__getitem__(name)
File "/usr/lib/python3.4/ctypes/__init__.py", line 369, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'history_set_pos' not found (ďż˝[ďż˝ďż˝ďż˝%ďż˝ďż˝Pďż˝ďż˝ďż˝)

# Fixed code
def foreign_shell_data(
    shell,
    interactive=True,
    login=False,
    envcmd=None,
    aliascmd=None,
    extra_args=(),
    currenv=None,
    safe=True,
    prevcmd="",
    postcmd="",
    funcscmd=None,
    sourcer=None,
    use_tmpfile=False,
    tmpfile_ext=None,
    runcmd=None,
    seterrprevcmd=None,
    seterrpostcmd=None,
):
    """Extracts data from a foreign (non-xonsh) shells. Currently this gets
    the environment, aliases, and functions but may be extended in the future.

    Parameters
    ----------
    shell : str
        The name of the shell, such as 'bash' or '/bin/sh'.
    interactive : bool, optional
        Whether the shell should be run in interactive mode.
    login : bool, optional
        Whether the shell should be a login shell.
    envcmd : str or None, optional
        The command to generate environment output with.
    aliascmd : str or None, optional
        The command to generate alias output with.
    extra_args : tuple of str, optional
        Addtional command line options to pass into the shell.
    currenv : tuple of items or None, optional
        Manual override for the current environment.
    safe : bool, optional
        Flag for whether or not to safely handle exceptions and other errors.
    prevcmd : str, optional
        A command to run in the shell before anything else, useful for
        sourcing and other commands that may require environment recovery.
    postcmd : str, optional
        A command to run after everything else, useful for cleaning up any
        damage that the prevcmd may have caused.
    funcscmd : str or None, optional
        This is a command or script that can be used to determine the names
        and locations of any functions that are native to the foreign shell.
        This command should print *only* a JSON object that maps
        function names to the filenames where the functions are defined.
        If this is None, then a default script will attempted to be looked
        up based on the shell name. Callable wrappers for these functions
        will be returned in the aliases dictionary.
    sourcer : str or None, optional
        How to source a foreign shell file for purposes of calling functions
        in that shell. If this is None, a default value will attempt to be
        looked up based on the shell name.
    use_tmpfile : bool, optional
        This specifies if the commands are written to a tmp file or just
        parsed directly to the shell
    tmpfile_ext : str or None, optional
        If tmpfile is True this sets specifies the extension used.
    runcmd : str or None, optional
        Command line switches to use when running the script, such as
        -c for Bash and /C for cmd.exe.
    seterrprevcmd : str or None, optional
        Command that enables exit-on-error for the shell that is run at the
        start of the script. For example, this is "set -e" in Bash. To disable
        exit-on-error behavior, simply pass in an empty string.
    seterrpostcmd : str or None, optional
        Command that enables exit-on-error for the shell that is run at the end
        of the script. For example, this is "if errorlevel 1 exit 1" in
        cmd.exe. To disable exit-on-error behavior, simply pass in an
        empty string.

    Returns
    -------
    env : dict
        Dictionary of shell's environment
    aliases : dict
        Dictionary of shell's alaiases, this includes foreign function
        wrappers.
    """
    cmd = [shell]
    cmd.extend(extra_args)  # needs to come here for GNU long options
    if interactive:
        cmd.append("-i")
    if login:
        cmd.append("-l")
    shkey = CANON_SHELL_NAMES[shell]
    envcmd = DEFAULT_ENVCMDS.get(shkey, "env") if envcmd is None else envcmd
    aliascmd = DEFAULT_ALIASCMDS.get(shkey, "alias") if aliascmd is None else aliascmd
    funcscmd = DEFAULT_FUNCSCMDS.get(shkey, "echo {}") if funcscmd is None else funcscmd
    tmpfile_ext = (
        DEFAULT_TMPFILE_EXT.get(shkey, "sh") if tmpfile_ext is None else tmpfile_ext
    )
    runcmd = DEFAULT_RUNCMD.get(shkey, "-c") if runcmd is None else runcmd
    seterrprevcmd = (
        DEFAULT_SETERRPREVCMD.get(shkey, "") if seterrprevcmd is None else seterrprevcmd
    )
    seterrpostcmd = (
        DEFAULT_SETERRPOSTCMD.get(shkey, "") if seterrpostcmd is None else seterrpostcmd
    )
    command = COMMAND.format(
        envcmd=envcmd,
        aliascmd=aliascmd,
        prevcmd=prevcmd,
        postcmd=postcmd,
        funcscmd=funcscmd,
        seterrprevcmd=seterrprevcmd,
        seterrpostcmd=seterrpostcmd,
    ).strip()

    cmd.append(runcmd)

    if not use_tmpfile:
        cmd.append(command)
    else:
        tmpfile = NamedTemporaryFile(suffix=tmpfile_ext, delete=False)
        tmpfile.write(command.encode("utf8"))
        tmpfile.close()
        cmd.append(tmpfile.name)

    if currenv is None and hasattr(builtins, "__xonsh_env__"):
        currenv = builtins.__xonsh_env__.detype()
    elif currenv is not None:
        currenv = dict(currenv)
    try:
        # start new session to avoid hangs (doesn't work on Cygwin though)
        newsess = not (sys.platform == "cygwin")
        s = subprocess.check_output(
            cmd,
            stderr=subprocess.PIPE,
            env=currenv,
            start_new_session=newsess,
            universal_newlines=True,
        )
    except (subprocess.CalledProcessError, FileNotFoundError):
        if not safe:
            raise
        return None, None
    finally:
        if use_tmpfile:
            os.remove(tmpfile.name)
    env = parse_env(s)
    aliases = parse_aliases(s)
    funcs = parse_funcs(s, shell=shell, sourcer=sourcer)
    aliases.update(funcs)
    return env, aliases