Repository: xonsh/xonsh

Issue:
Occasional error when xonsh start - JSONDecodeError
```
hugo@mbp: ~$ Exception in thread Thread-2:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 914,r
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/xonsh/ptk/n
    lj = lazyjson.LazyJSON(f, reopen=False)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/xonsh/lazy_
    self._load_index()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/xonsh/lazyx
    locs = json.loads(locs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/__init__.py", line s
    return _default_decoder.decode(s)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/decoder.py", line 3e
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/decoder.py", line 3e
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
```

No investigations yet, just put some tracebacks here.



Discussion:
Not in Xonsh but I have had this error about 1000 times in another Python app which is trying to read a json file as it's being written to disk. This might be fixed by catching the JSONDecodeError (or ValueError for python 3.4) and retrying the load, but might be a chance it could fail again. 

i also sometimes get a json related error when starting xonsh, dunno if this relates to this issue

```
Exception ignored in: <bound method LazyJSON.__del__ of <xonsh.lazyjson.LazyJSON object at 0x7f4603ad5400>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/xonsh-0.3.4-py3.5.egg/xonsh/lazyjson.py", line 213, in __del__
    self.close()
  File "/usr/local/lib/python3.5/dist-packages/xonsh-0.3.4-py3.5.egg/xonsh/lazyjson.py", line 218, in close
    self._f.close()
OSError: [Errno 9] Bad file descriptor
```

Thanks for reporting these issues @mitnk and @laerus. I have never seen these.  Do you have any steps to reproduce?

@scopatz i can't find a way to reproduce this, it seems a little random, if i find out more i'll open a new issue

Ok sounds like a plan!

It's very rare and usually happened after installing a fresh commit of xonsh copy (but not every time). It just happened on my side again:

```
Last login: Thu Jun 23 11:05:31 on ttys011
hugo@mbp: ~$ Exception in thread Thread-3:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/xonsh/ptk/history.py", line 59, in run
    lj = lazyjson.LazyJSON(f, reopen=False)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 511, in __init__
    self._load_index()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 539, in _load_index
    locs = json.loads(locs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

hugo@mbp: ~$
```

And, it didn't crash the xonsh session. 

@scopatz, I realize it is unorthodox but I recommend handling this exception in the master branch which would allow more information to be reported (e.g. which file is being affected by this). Because it is rare you will need many users to get a hit. In the exception handling you can put a message to report the information to this issue thread. Again, I realize it is not common practice but the traceback is so lacking I don't think we'll solve it just by people reporting tracebacks here.

> @scopatz, I realize it is unorthodox but I recommend handling this exception in the master branch

This exception used to be handled and then someone removed it for reasons I don't fully understand...


Resolving patch:
diff --git a/xonsh/ptk/history.py b/xonsh/ptk/history.py
--- a/xonsh/ptk/history.py
+++ b/xonsh/ptk/history.py
@@ -69,7 +69,7 @@ def run(self):
                                 continue
                         buf.reset(initial_document=buf.document)
                 lj.close()
-            except (IOError, OSError):
+            except (IOError, OSError, ValueError):
                 continue
 
     def _buf(self):
diff --git a/xonsh/readline_shell.py b/xonsh/readline_shell.py
--- a/xonsh/readline_shell.py
+++ b/xonsh/readline_shell.py
@@ -469,5 +469,5 @@ def run(self):
                             RL_LIB.history_set_pos(i)
                         i += 1
                 lj.close()
-            except (IOError, OSError):
+            except (IOError, OSError, ValueError):
                 continue
diff --git a/xonsh/tools.py b/xonsh/tools.py
--- a/xonsh/tools.py
+++ b/xonsh/tools.py
@@ -583,10 +583,15 @@ def suggest_commands(cmd, env, aliases):
 
 def print_exception(msg=None):
     """Print exceptions with/without traceback."""
-    env = getattr(builtins, '__xonsh_env__', os.environ)
+    env = getattr(builtins, '__xonsh_env__', None)
     # flags indicating whether the traceback options have been manually set
-    manually_set_trace = env.is_manually_set('XONSH_SHOW_TRACEBACK')
-    manually_set_logfile = env.is_manually_set('XONSH_TRACEBACK_LOGFILE')
+    if env is None:
+        env = os.environ
+        manually_set_trace = 'XONSH_SHOW_TRACEBACK' in env
+        manually_set_logfile ='XONSH_TRACEBACK_LOGFILE' in env
+    else:
+        manually_set_trace = env.is_manually_set('XONSH_SHOW_TRACEBACK')
+        manually_set_logfile = env.is_manually_set('XONSH_TRACEBACK_LOGFILE')
     if (not manually_set_trace) and (not manually_set_logfile):
         # Notify about the traceback output possibility if neither of
         # the two options have been manually set
@@ -604,7 +609,6 @@ def print_exception(msg=None):
             sys.stderr.write('xonsh: To log full traceback to a file set: '
                              '$XONSH_TRACEBACK_LOGFILE = <filename>\n')
         traceback.print_exc()
-
     # additionally, check if a file for traceback logging has been
     # specified and convert to a proper option if needed
     log_file = env.get('XONSH_TRACEBACK_LOGFILE', None)


Test patch: