Repository: xonsh/xonsh

Issue:
Readline Cannot Find Init File
Soooo, I must be missing something, but I can't seem to figure out why on xonsh starting I'm always getting this error:

```
$ xonsh
FileNotFoundError: [Errno 2] No such file or directory
xonsh: could not load readline default init file.
```

I've narrowed it down to https://github.com/scopatz/xonsh/blob/master/xonsh/readline_shell.py#L75-L79 (obviously), but without being too familiar with `readline`, it is not obvious to me what the fix is.

Can anyone shed any light on this?



Discussion:
+1

Hey @fxfitz , @smogg -- which OS are you on?

Thanks for reporting!

Can you try setting `$XONSH_SHOW_TRACEBACK = True` in your `.xonshrc` file?  That should cause a more complete traceback to show up.  Can you paste that here?

Also, can you please let us know what is the output of running the `xonfig` command?  I know different platforms' readlines have their own quirks...

Here's the traceback:

```
$ xonsh
Traceback (most recent call last):
  File "/Users/fxfitz/.pyenv/versions/3.5.0/lib/python3.5/site-packages/xonsh/readline_shell.py", line 76, in setup_readline
    readline.read_init_file()
FileNotFoundError: [Errno 2] No such file or directory
xonsh: could not load readline default init file.
```

And from xonfig:

```
$ xonfig
+------------------+-------+
| xonsh            | 0.3.2 |
| Python           | 3.5.0 |
| PLY              | 3.7   |
| have readline    | True  |
| prompt toolkit   | None  |
| pygments         | 2.1.3 |
| on posix         | True  |
| on linux         | False |
| on darwin        | True  |
| on windows       | False |
| is superuser     | False |
| default encoding | utf-8 |
+------------------+-------+
```

@gforsyth OSX 10.11.4

Traceback:

```
File "/usr/local/lib/python3.5/site-packages/xonsh/readline_shell.py", line 76, in setup_readline
    readline.read_init_file()
FileNotFoundError: [Errno 2] No such file or directory
xonsh: could not load readline default init file.
```

xonfig:

```
+------------------+-------+
| xonsh            | 0.3.2 |
| Python           | 3.5.1 |
| PLY              | 3.7   |
| have readline    | True  |
| prompt toolkit   | None  |
| pygments         | 2.1.3 |
| on posix         | True  |
| on linux         | False |
| on darwin        | True  |
| on windows       | False |
| is superuser     | False |
| default encoding | utf-8 |
+------------------+-------+
```

Also, I'm on OSX (El Cap).

Hmm I would have to guess that there is something weird about readline on Mac.  Unfortunately, I don't have a Mac machine to test this.  @gforsyth, are you a Mac person?  If not, we may have to wait for @scopatz (who I believe has a Mac).

In the meantime, the [readline docs](https://docs.python.org/3/library/readline.html) say:

> The underlying Readline library API may be implemented by the libedit library instead of GNU readline. On MacOS X the readline module detects which library is being used at run time.
> The configuration file for libedit is different from that of GNU readline. If you programmatically load configuration strings you can check for the text “libedit” in readline.__doc__ to differentiate between GNU readline and libedit.

Can you try running Python, importing readline, printing `readline.__doc__`, and letting us know the result?

@adqm, I am not.  And I'm pretty sure @scopatz switched to Linux, although he may still have a mac laptop lying around?  Or, I can grab one of the hundreds of macs around me at PyCon, but people seem to react badly to that...

In the meantime, it looks like IPython handles loading the init files in a slightly nicer way.  I'll try bringing some of their code over to see if that fixes it.

One workaround would be to install `prompt_toolkit` via `pip` (or similar) and set `$SHELL_TYPE = "prompt_toolkit"` in your `.xonshrc` file, which would use that shell instead of using `readline` (some would even say the prompt toolkit shell is better than the readline one).

```
$ python
Python 3.5.0 (default, Oct  6 2015, 17:53:19) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.72)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import readline
>>> readline.__doc__
'Importing this module enables command line editing using GNU readline.'
```

I'll give the `prompt_toolkit` a try!

`prompt_toolkit` worked! :-D

it did work for me 2

@fxfitz, @smogg: Great!  I'll still put in the fix for readline, though, in case others encounter this.


Resolving patch:
diff --git a/xonsh/readline_shell.py b/xonsh/readline_shell.py
--- a/xonsh/readline_shell.py
+++ b/xonsh/readline_shell.py
@@ -1,10 +1,19 @@
 # -*- coding: utf-8 -*-
-"""The readline based xonsh shell."""
+"""The readline based xonsh shell.
+
+Portions of this code related to initializing the readline library
+are included from the IPython project.  The IPython project is:
+    * Copyright (c) 2008-2014, IPython Development Team
+    * Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
+    * Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
+    * Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
+"""
 import os
 import sys
 import time
 import select
 import builtins
+import importlib
 from cmd import Cmd
 from threading import Thread
 from collections import deque
@@ -14,7 +23,7 @@
 from xonsh.ansi_colors import partial_color_format, color_style_names, color_style
 from xonsh.environ import partial_format_prompt, multiline_prompt
 from xonsh.tools import print_exception
-from xonsh.platform import HAS_PYGMENTS, ON_WINDOWS, ON_CYGWIN
+from xonsh.platform import HAS_PYGMENTS, ON_WINDOWS, ON_CYGWIN, ON_DARWIN
 
 if HAS_PYGMENTS:
     from xonsh import pyghooks
@@ -34,12 +43,20 @@ def setup_readline():
     global RL_COMPLETION_SUPPRESS_APPEND, RL_LIB, RL_CAN_RESIZE, RL_STATE, readline
     if RL_COMPLETION_SUPPRESS_APPEND is not None:
         return
-    try:
-        import readline
-    except ImportError:
+    for _rlmod_name in ('gnureadline', 'readline'):
+        try:
+            readline = importlib.import_module(_rlmod_name)
+            sys.modules['readline'] = readline
+        except ImportError:
+            pass
+        else:
+            break
+    if readline is None:
+        print("No readline implementation available.  Skipping setup.")
         return
     import ctypes
     import ctypes.util
+    uses_libedit = readline.__doc__ and 'libedit' in readline.__doc__
     readline.set_completer_delims(' \t\n')
     # Cygwin seems to hang indefinitely when querying the readline lib
     if (not ON_CYGWIN) and (not readline.__file__.endswith('.py')):
@@ -67,16 +84,36 @@ def setup_readline():
 
     # handle tab completion differences found in libedit readline compatibility
     # as discussed at http://stackoverflow.com/a/7116997
-    if readline.__doc__ and 'libedit' in readline.__doc__:
+    if uses_libedit and ON_DARWIN:
         readline.parse_and_bind("bind ^I rl_complete")
+        print('\n'.join(['', "*"*78,
+            "libedit detected - readline will not be well behaved, including but not limited to:",
+            "   * crashes on tab completion",
+            "   * incorrect history navigation",
+            "   * corrupting long-lines",
+            "   * failure to wrap or indent lines properly",
+            "",
+            "It is highly recommended that you install gnureadline, which is installable with:",
+            "     pip install gnureadline",
+            "*"*78]), file=sys.stderr)
     else:
         readline.parse_and_bind("tab: complete")
     # try to load custom user settings
-    try:
-        readline.read_init_file()
-    except Exception:
-        # this seems to fail with libedit
-        print_exception('xonsh: could not load readline default init file.')
+    inputrc_name = os.environ.get('INPUTRC')
+    if inputrc_name is None:
+        if uses_libedit:
+            inputrc_name = '.editrc'
+        else:
+            inputrc_name = '.inputrc'
+        inputrc_name = os.path.join(os.path.expanduser('~'), inputrc_name)
+    if (not ON_WINDOWS) and (not os.path.isfile(inputrc_name)):
+        inputrc_name = '/etc/inputrc'
+    if os.path.isfile(inputrc_name):
+        try:
+            readline.read_init_file(inputrc_name)
+        except Exception:
+            # this seems to fail with libedit
+            print_exception('xonsh: could not load readline default init file.')
 
 
 def teardown_readline():


Test patch: