Repository: hylang/hy

Issue:
REPL crashes when ~/.hy-history is inaccessible
I've been working on updating the Hy package in Debian and in running the tests, I've noticed that the `test_bin` tests appear to expect to be able to do something with `~/.hy-history` (not sure if it's trying to read or write) but I had to set `HOME` to a real directory after which they passed.  Looking at the tests, I imagine it's happening because they're interacting with the REPL via stdin so it's trying to load and/or use the history file?


Discussion:
Probably. Shouldn't `HOME` always be a real directory?
In most Debian build contexts it's typically set to something obviously bogus like `/nonexistent` to help surface bugs like software builds or tests touching something in `HOME`. :sweat_smile:
Hmm, this does seem like Debian creating trouble for itself, then. Still, the REPL shouldn't crash just because there's an error writing to `~/.hy-history`, nor do I think any of the tests should fail. Which tests failed?
<details>

```console
I have no name!@dfa5f6c602a3:/tmp/hy$ pytest -k test_bin
============================= test session starts ==============================
platform linux -- Python 3.7.2, pytest-5.1.0, py-1.8.0, pluggy-0.12.0
rootdir: /tmp/hy, inifile: setup.cfg
collected 605 items / 553 deselected / 52 selected                             

tests/test_bin.py FFFFFFFFFFFFF..FFF..............................F.F    [ 98%]
tests/native_tests/language.hy .                                         [100%]

=================================== FAILURES ===================================
_________________________________ test_bin_hy __________________________________

    def test_bin_hy():
>       run_cmd("hy", "")

tests/test_bin.py:57: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '', expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d75fd0>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d75fd0>> = <subprocess.Popen object at 0x7fa779d75fd0>.wait

tests/test_bin.py:42: AssertionError
______________________________ test_bin_hy_stdin _______________________________

    def test_bin_hy_stdin():
>       output, _ = run_cmd("hy", '(koan)')

tests/test_bin.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(koan)', expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779dd0c50>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779dd0c50>> = <subprocess.Popen object at 0x7fa779dd0c50>.wait

tests/test_bin.py:42: AssertionError
_________________________ test_bin_hy_stdin_multiline __________________________

    def test_bin_hy_stdin_multiline():
>       output, _ = run_cmd("hy", '(+ "a" "b"\n"c" "d")')

tests/test_bin.py:74: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(+ "a" "b"\n"c" "d")', expect = 0
dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779e68fd0>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779e68fd0>> = <subprocess.Popen object at 0x7fa779e68fd0>.wait

tests/test_bin.py:42: AssertionError
_____________________________ test_bin_hy_history ______________________________

    def test_bin_hy_history():
        output, _ = run_cmd("hy", '''(+ "a" "b")
                                     (+ "c" "d")
                                     (+ "e" "f")
>                                    (.format "*1: {}, *2: {}, *3: {}," *1 *2 *3)''')

tests/test_bin.py:82: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy']
stdin_data = '(+ "a" "b")\n                                 (+ "c" "d")\n                                 (+ "e" "f")\n                                 (.format "*1: {}, *2: {}, *3: {}," *1 *2 *3)'
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779e075f8>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779e075f8>> = <subprocess.Popen object at 0x7fa779e075f8>.wait

tests/test_bin.py:42: AssertionError
__________________________ test_bin_hy_stdin_comments __________________________

    def test_bin_hy_stdin_comments():
>       _, err_empty = run_cmd("hy", '')

tests/test_bin.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '', expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d19358>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d19358>> = <subprocess.Popen object at 0x7fa779d19358>.wait

tests/test_bin.py:42: AssertionError
_________________________ test_bin_hy_stdin_assignment _________________________

    def test_bin_hy_stdin_assignment():
        # If the last form is an assignment, don't print the value.
    
>       output, _ = run_cmd("hy", '(setv x (+ "A" "Z"))')

tests/test_bin.py:104: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(setv x (+ "A" "Z"))', expect = 0
dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779df63c8>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779df63c8>> = <subprocess.Popen object at 0x7fa779df63c8>.wait

tests/test_bin.py:42: AssertionError
__________________________ test_bin_hy_stdin_as_arrow __________________________

    def test_bin_hy_stdin_as_arrow():
        # https://github.com/hylang/hy/issues/1255
>       output, _ = run_cmd("hy", "(as-> 0 it (inc it) (inc it))")

tests/test_bin.py:118: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(as-> 0 it (inc it) (inc it))', expect = 0
dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779b98b70>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779b98b70>> = <subprocess.Popen object at 0x7fa779b98b70>.wait

tests/test_bin.py:42: AssertionError
_________________ test_bin_hy_stdin_error_underline_alignment __________________

    def test_bin_hy_stdin_error_underline_alignment():
>       _, err = run_cmd("hy", "(defmacro mabcdefghi [x] x)\n(mabcdefghi)")

tests/test_bin.py:123: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(defmacro mabcdefghi [x] x)\n(mabcdefghi)'
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa77a19dda0>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa77a19dda0>> = <subprocess.Popen object at 0x7fa77a19dda0>.wait

tests/test_bin.py:42: AssertionError
_________________________ test_bin_hy_stdin_except_do __________________________

    def test_bin_hy_stdin_except_do():
        # https://github.com/hylang/hy/issues/533
    
>       output, _ = run_cmd("hy", '(try (/ 1 0) (except [ZeroDivisionError] "hello"))')  # noqa

tests/test_bin.py:139: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(try (/ 1 0) (except [ZeroDivisionError] "hello"))'
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779bb20f0>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779bb20f0>> = <subprocess.Popen object at 0x7fa779bb20f0>.wait

tests/test_bin.py:42: AssertionError
__________________ test_bin_hy_stdin_unlocatable_hytypeerror ___________________

    def test_bin_hy_stdin_unlocatable_hytypeerror():
        # https://github.com/hylang/hy/issues/1412
        # The chief test of interest here is the returncode assertion
        # inside run_cmd.
        _, err = run_cmd("hy", """
            (import hy.errors)
>           (raise (hy.errors.HyTypeError (+ "A" "Z") None '[] None))""")

tests/test_bin.py:159: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy']
stdin_data = '\n        (import hy.errors)\n        (raise (hy.errors.HyTypeError (+ "A" "Z") None \'[] None))'
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d92160>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d92160>> = <subprocess.Popen object at 0x7fa779d92160>.wait

tests/test_bin.py:42: AssertionError
________________________ test_bin_hy_error_parts_length ________________________

    def test_bin_hy_error_parts_length():
        """Confirm that exception messages print arrows surrounding the affected
        expression."""
        prg_str = """
        (import hy.errors
                [hy.importer [hy-parse]])
    
        (setv test-expr (hy-parse "(+ 1\n\n'a 2 3\n\n 1)"))
        (setv test-expr.start-line {})
        (setv test-expr.start-column {})
        (setv test-expr.end-column {})
    
        (raise (hy.errors.HyLanguageError
                 "this\nis\na\nmessage"
                 test-expr
                 None
                 None))
        """
    
        # Up-arrows right next to each other.
>       _, err = run_cmd("hy", prg_str.format(3, 1, 2))

tests/test_bin.py:183: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy']
stdin_data = '\n    (import hy.errors\n            [hy.importer [hy-parse]])\n\n    (setv test-expr (hy-parse "(+ 1\n\n\'a 2 3\n\n ...nguageError\n             "this\nis\na\nmessage"\n             test-expr\n             None\n             None))\n    '
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779dd0dd8>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779dd0dd8>> = <subprocess.Popen object at 0x7fa779dd0dd8>.wait

tests/test_bin.py:42: AssertionError
__________________________ test_bin_hy_stdin_bad_repr __________________________

    def test_bin_hy_stdin_bad_repr():
        # https://github.com/hylang/hy/issues/1389
        output, err = run_cmd("hy", """
             (defclass BadRepr [] (defn __repr__ [self] (/ 0)))
             (BadRepr)
>            (+ "A" "Z")""")

tests/test_bin.py:224: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy']
stdin_data = '\n         (defclass BadRepr [] (defn __repr__ [self] (/ 0)))\n         (BadRepr)\n         (+ "A" "Z")'
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d75588>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d75588>> = <subprocess.Popen object at 0x7fa779d75588>.wait

tests/test_bin.py:42: AssertionError
__________________________ test_bin_hy_stdin_hy_repr ___________________________

    def test_bin_hy_stdin_hy_repr():
>       output, _ = run_cmd("hy", '(+ [1] [2])')

tests/test_bin.py:230: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(+ [1] [2])', expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa77a69a940>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa77a69a940>> = <subprocess.Popen object at 0x7fa77a69a940>.wait

tests/test_bin.py:42: AssertionError
_______________________________ test_bin_hy_icmd _______________________________

    def test_bin_hy_icmd():
>       output, _ = run_cmd("hy -i \"(koan)\"", "(ideas)")

tests/test_bin.py:271: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy', '-i', '(koan)'], stdin_data = '(ideas)', expect = 0
dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779dd8438>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779dd8438>> = <subprocess.Popen object at 0x7fa779dd8438>.wait

tests/test_bin.py:42: AssertionError
____________________________ test_bin_hy_icmd_file _____________________________

    def test_bin_hy_icmd_file():
>       output, _ = run_cmd("hy -i resources/icmd_test_file.hy", "(ideas)")

tests/test_bin.py:277: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy', '-i', 'resources/icmd_test_file.hy'], stdin_data = '(ideas)'
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779db7588>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779db7588>> = <subprocess.Popen object at 0x7fa779db7588>.wait

tests/test_bin.py:42: AssertionError
___________________________ test_bin_hy_icmd_and_spy ___________________________

    def test_bin_hy_icmd_and_spy():
>       output, _ = run_cmd("hy -i \"(+ [] [])\" --spy", "(+ 1 1)")

tests/test_bin.py:286: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy', '-i', '(+ [] [])', '--spy'], stdin_data = '(+ 1 1)', expect = 0
dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d1d710>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779d1d710>> = <subprocess.Popen object at 0x7fa779d1d710>.wait

tests/test_bin.py:42: AssertionError
______________________ test_bin_hy_circular_macro_require ______________________

    def test_bin_hy_circular_macro_require():
        """Confirm that macros can require themselves during expansion and when
        run from the command line."""
    
        # First, with no bytecode
        test_file = "tests/resources/bin/circular_macro_require.hy"
        rm(cache_from_source(test_file))
        assert not os.path.exists(cache_from_source(test_file))
>       output, _ = run_cmd("hy {}".format(test_file))

tests/test_bin.py:464: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy', 'tests/resources/bin/circular_macro_require.hy'], stdin_data = None
expect = 0, dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa779df8438>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa779df8438>> = <subprocess.Popen object at 0x7fa779df8438>.wait

tests/test_bin.py:42: AssertionError
____________________________ test_bin_hy_tracebacks ____________________________

    def test_bin_hy_tracebacks():
        """Make sure the printed tracebacks are correct."""
    
        # We want the filtered tracebacks.
        os.environ['HY_DEBUG'] = ''
    
        def req_err(x):
            assert (x == 'hy.errors.HyRequireError: No module named '
                "'not_a_real_module'")
    
        # Modeled after
        #   > python -c 'import not_a_real_module'
        #   Traceback (most recent call last):
        #     File "<string>", line 1, in <module>
        #   ImportError: No module named not_a_real_module
>       _, error = run_cmd('hy', '(require not-a-real-module)')

tests/test_bin.py:506: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cmd = ['hy'], stdin_data = '(require not-a-real-module)', expect = 0
dontwritebytecode = False

    def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
        env = dict(os.environ)
        if dontwritebytecode:
            env["PYTHONDONTWRITEBYTECODE"] = "1"
        else:
            env.pop("PYTHONDONTWRITEBYTECODE", None)
    
        cmd = shlex.split(cmd)
        cmd[0] = os.path.join(hy_dir, cmd[0])
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=False,
                             env=env)
        output = p.communicate(input=stdin_data)
>       assert p.wait() == expect
E       assert 1 == 0
E        +  where 1 = <bound method Popen.wait of <subprocess.Popen object at 0x7fa77a19d7f0>>()
E        +    where <bound method Popen.wait of <subprocess.Popen object at 0x7fa77a19d7f0>> = <subprocess.Popen object at 0x7fa77a19d7f0>.wait

tests/test_bin.py:42: AssertionError
================ 18 failed, 34 passed, 553 deselected in 15.84s ================
```

</details>
Thanks. Try this patch.

```diff
From e4bbc8604008ca453279f31d6068fc97f7d2099d Mon Sep 17 00:00:00 2001
From: Kodi Arfer <git@arfer.net>
Date: Fri, 16 Aug 2019 18:49:02 -0400
Subject: [PATCH] Avoid a crash when we can't access a history file

---
 hy/completer.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/hy/completer.py b/hy/completer.py
index b1969c1..86ceb74 100644
--- a/hy/completer.py
+++ b/hy/completer.py
@@ -123,7 +123,7 @@ def completion(completer=None):
         try:
             readline.read_history_file(history)
         except IOError:
-            open(history, 'a').close()
+            pass #open(history, 'a').close()
 
         readline.parse_and_bind(readline_bind)
 
@@ -131,4 +131,7 @@ def completion(completer=None):
         yield
     finally:
         if docomplete:
-            readline.write_history_file(history)
+            try:
+                readline.write_history_file(history)
+            except IOError:
+                pass
-- 
2.20.1
```
Works great! (and seems like pretty sane behavior in the face of something like a read-only `HOME`, etc IMO)

Resolving patch:
diff --git a/hy/completer.py b/hy/completer.py
--- a/hy/completer.py
+++ b/hy/completer.py
@@ -123,7 +123,7 @@ def completion(completer=None):
         try:
             readline.read_history_file(history)
         except IOError:
-            open(history, 'a').close()
+            pass
 
         readline.parse_and_bind(readline_bind)
 
@@ -131,4 +131,7 @@ def completion(completer=None):
         yield
     finally:
         if docomplete:
-            readline.write_history_file(history)
+            try:
+                readline.write_history_file(history)
+            except IOError:
+                pass


Test patch: