# Buggy code
def run(user_ns=None):
    a = docopt.docopt(__doc__)

    vi_mode = bool(a["--vi"])
    config_dir = os.path.expanduser(a["--config-dir"] or "~/.ptpython/")

    # Create config directory.
    if not os.path.isdir(config_dir):
        os.mkdir(config_dir)

    # If IPython is not available, show message and exit here with error status
    # code.
    try:
        import IPython
    except ImportError:
        print("IPython not found. Please install IPython (pip install ipython).")
        sys.exit(1)
    else:
        from ptpython.ipython import embed
        from ptpython.repl import run_config, enable_deprecation_warnings

    # Add the current directory to `sys.path`.
    if sys.path[0] != "":
        sys.path.insert(0, "")

    # When a file has been given, run that, otherwise start the shell.
    if a["<arg>"] and not a["--interactive"]:
        sys.argv = a["<arg>"]
        six.exec_(compile(open(a["<arg>"][0], "rb").read(), a["<arg>"][0], "exec"))
    else:
        enable_deprecation_warnings()

        # Create an empty namespace for this interactive shell. (If we don't do
        # that, all the variables from this function will become available in
        # the IPython shell.)
        if user_ns is None:
            user_ns = {}

        # Startup path
        startup_paths = []
        if "PYTHONSTARTUP" in os.environ:
            startup_paths.append(os.environ["PYTHONSTARTUP"])

        # --interactive
        if a["--interactive"]:
            startup_paths.append(a["--interactive"])
            sys.argv = [a["--interactive"]] + a["<arg>"]

        # exec scripts from startup paths
        for path in startup_paths:
            if os.path.exists(path):
                with open(path, "r") as f:
                    code = compile(f.read(), path, "exec")
                    six.exec_(code, user_ns, user_ns)
            else:
                print("File not found: {}\n\n".format(path))
                sys.exit(1)

        # Apply config file
        def configure(repl):
            path = os.path.join(config_dir, "config.py")
            if os.path.exists(path):
                run_config(repl, path)

        # Run interactive shell.
        embed(
            vi_mode=vi_mode,
            history_filename=os.path.join(config_dir, "history"),
            configure=configure,
            user_ns=user_ns,
            title="IPython REPL (ptipython)",
        )


# Traceback (UnicodeDecodeError)
Traceback (most recent call last):
File "c:\python36\lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "c:\python36\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Python36\Scripts\ptpython.exe\__main__.py", line 9, in <module>
File "c:\python36\lib\site-packages\ptpython\entry_points\run_ptpython.py", line 74, in run
title='Python REPL (ptpython)')
File "c:\python36\lib\site-packages\ptpython\repl.py", line 320, in embed
cli.run()
File "c:\python36\lib\site-packages\prompt_toolkit\interface.py", line 404, in run
self.on_start.fire()
File "c:\python36\lib\site-packages\prompt_toolkit\utils.py", line 60, in fire
self()
File "c:\python36\lib\site-packages\prompt_toolkit\utils.py", line 56, in __call__
handler(self.sender)
File "c:\python36\lib\site-packages\ptpython\repl.py", line 62, in _on_start
code = compile(f.read(), path, 'exec')
File "c:\python36\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 2: character maps to <undefined>

# Fixed code
def run(user_ns=None):
    a = docopt.docopt(__doc__)

    vi_mode = bool(a["--vi"])
    config_dir = os.path.expanduser(a["--config-dir"] or "~/.ptpython/")

    # Create config directory.
    if not os.path.isdir(config_dir):
        os.mkdir(config_dir)

    # If IPython is not available, show message and exit here with error status
    # code.
    try:
        import IPython
    except ImportError:
        print("IPython not found. Please install IPython (pip install ipython).")
        sys.exit(1)
    else:
        from ptpython.ipython import embed
        from ptpython.repl import run_config, enable_deprecation_warnings

    # Add the current directory to `sys.path`.
    if sys.path[0] != "":
        sys.path.insert(0, "")

    # When a file has been given, run that, otherwise start the shell.
    if a["<arg>"] and not a["--interactive"]:
        sys.argv = a["<arg>"]
        path = a["<arg>"][0]
        with open(path, "rb") as f:
            code = compile(f.read(), path, "exec")
            six.exec_(code)
    else:
        enable_deprecation_warnings()

        # Create an empty namespace for this interactive shell. (If we don't do
        # that, all the variables from this function will become available in
        # the IPython shell.)
        if user_ns is None:
            user_ns = {}

        # Startup path
        startup_paths = []
        if "PYTHONSTARTUP" in os.environ:
            startup_paths.append(os.environ["PYTHONSTARTUP"])

        # --interactive
        if a["--interactive"]:
            startup_paths.append(a["--interactive"])
            sys.argv = [a["--interactive"]] + a["<arg>"]

        # exec scripts from startup paths
        for path in startup_paths:
            if os.path.exists(path):
                with open(path, "rb") as f:
                    code = compile(f.read(), path, "exec")
                    six.exec_(code, user_ns, user_ns)
            else:
                print("File not found: {}\n\n".format(path))
                sys.exit(1)

        # Apply config file
        def configure(repl):
            path = os.path.join(config_dir, "config.py")
            if os.path.exists(path):
                run_config(repl, path)

        # Run interactive shell.
        embed(
            vi_mode=vi_mode,
            history_filename=os.path.join(config_dir, "history"),
            configure=configure,
            user_ns=user_ns,
            title="IPython REPL (ptipython)",
        )