prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN 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?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `hy/completer.py`
  Content:
  ```
  1 # Copyright 2019 the authors.
  2 # This file is part of Hy, which is free software licensed under the Expat
  3 # license. See the LICENSE.
  4 
  5 import contextlib
  6 import os
  7 import re
  8 import sys
  9 import builtins
  10 
  11 import hy.macros
  12 import hy.compiler
  13 
  14 
  15 docomplete = True
  16 
  17 try:
  18     import readline
  19 except ImportError:
  20     try:
  21         import pyreadline.rlmain
  22         import pyreadline.unicode_helper  # NOQA
  23         import readline
  24     except ImportError:
  25         docomplete = False
  26 
  27 if docomplete:
  28     if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
  29         readline_bind = "bind ^I rl_complete"
  30     else:
  31         readline_bind = "tab: complete"
  32 
  33 
  34 class Completer(object):
  35 
  36     def __init__(self, namespace={}):
  37         if not isinstance(namespace, dict):
  38             raise TypeError('namespace must be a dictionary')
  39         self.namespace = namespace
  40         self.path = [hy.compiler._special_form_compilers,
  41                      builtins.__dict__,
  42                      namespace]
  43 
  44         self.tag_path = []
  45 
  46         namespace.setdefault('__macros__', {})
  47         namespace.setdefault('__tags__', {})
  48 
  49         self.path.append(namespace['__macros__'])
  50         self.tag_path.append(namespace['__tags__'])
  51 
  52     def attr_matches(self, text):
  53         # Borrowed from IPython's completer
  54         m = re.match(r"(\S+(\.[\w-]+)*)\.([\w-]*)$", text)
  55 
  56         if m:
  57             expr, attr = m.group(1, 3)
  58             attr = attr.replace("-", "_")
  59             expr = expr.replace("-", "_")
  60         else:
  61             return []
  62 
  63         try:
  64             obj = eval(expr, self.namespace)
  65             words = dir(obj)
  66         except Exception:
  67             return []
  68 
  69         n = len(attr)
  70         matches = []
  71         for w in words:
  72             if w[:n] == attr:
  73                 matches.append("{}.{}".format(
  74                     expr.replace("_", "-"), w.replace("_", "-")))
  75         return matches
  76 
  77     def global_matches(self, text):
  78         matches = []
  79         for p in self.path:
  80             for k in p.keys():
  81                 if isinstance(k, str):
  82                     k = k.replace("_", "-")
  83                     if k.startswith(text):
  84                         matches.append(k)
  85         return matches
  86 
  87     def tag_matches(self, text):
  88         text = text[1:]
  89         matches = []
  90         for p in self.tag_path:
  91             for k in p.keys():
  92                 if isinstance(k, str):
  93                     if k.startswith(text):
  94                         matches.append("#{}".format(k))
  95         return matches
  96 
  97     def complete(self, text, state):
  98         if text.startswith("#"):
  99             matches = self.tag_matches(text)
  100         elif "." in text:
  101             matches = self.attr_matches(text)
  102         else:
  103             matches = self.global_matches(text)
  104         try:
  105             return matches[state]
  106         except IndexError:
  107             return None
  108 
  109 
  110 @contextlib.contextmanager
  111 def completion(completer=None):
  112     delims = "()[]{} "
  113     if not completer:
  114         completer = Completer()
  115 
  116     if docomplete:
  117         readline.set_completer(completer.complete)
  118         readline.set_completer_delims(delims)
  119 
  120         history = os.path.expanduser("~/.hy-history")
  121         readline.parse_and_bind("set blink-matching-paren on")
  122 
  123         try:
  124             readline.read_history_file(history)
  125         except IOError:
  126             open(history, 'a').close()
  127 
  128         readline.parse_and_bind(readline_bind)
  129 
  130     try:
  131         yield
  132     finally:
  133         if docomplete:
  134             readline.write_history_file(history)
  135
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/hy/completer.py b/hy/completer.py
  --- a/hy/completer.py
  +++ b/hy/completer.py
  @@ -123,7 +123,7 @@
           try:
               readline.read_history_file(history)
           except IOError:
  -            open(history, 'a').close()
  +            pass
   
           readline.parse_and_bind(readline_bind)
   
  @@ -131,4 +131,7 @@
           yield
       finally:
           if docomplete:
  -            readline.write_history_file(history)
  +            try:
  +                readline.write_history_file(history)
  +            except IOError:
  +                pass
  
verification_info: {"golden_diff": "diff --git a/hy/completer.py b/hy/completer.py\n--- a/hy/completer.py\n+++ b/hy/completer.py\n@@ -123,7 +123,7 @@\n         try:\n             readline.read_history_file(history)\n         except IOError:\n-            open(history, 'a').close()\n+            pass\n \n         readline.parse_and_bind(readline_bind)\n \n@@ -131,4 +131,7 @@\n         yield\n     finally:\n         if docomplete:\n-            readline.write_history_file(history)\n+            try:\n+                readline.write_history_file(history)\n+            except IOError:\n+                pass\n", "issue": "REPL crashes when ~/.hy-history is inaccessible\nI'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?\n", "before_files": [{"content": "# Copyright 2019 the authors.\n# This file is part of Hy, which is free software licensed under the Expat\n# license. See the LICENSE.\n\nimport contextlib\nimport os\nimport re\nimport sys\nimport builtins\n\nimport hy.macros\nimport hy.compiler\n\n\ndocomplete = True\n\ntry:\n    import readline\nexcept ImportError:\n    try:\n        import pyreadline.rlmain\n        import pyreadline.unicode_helper  # NOQA\n        import readline\n    except ImportError:\n        docomplete = False\n\nif docomplete:\n    if sys.platform == 'darwin' and 'libedit' in readline.__doc__:\n        readline_bind = \"bind ^I rl_complete\"\n    else:\n        readline_bind = \"tab: complete\"\n\n\nclass Completer(object):\n\n    def __init__(self, namespace={}):\n        if not isinstance(namespace, dict):\n            raise TypeError('namespace must be a dictionary')\n        self.namespace = namespace\n        self.path = [hy.compiler._special_form_compilers,\n                     builtins.__dict__,\n                     namespace]\n\n        self.tag_path = []\n\n        namespace.setdefault('__macros__', {})\n        namespace.setdefault('__tags__', {})\n\n        self.path.append(namespace['__macros__'])\n        self.tag_path.append(namespace['__tags__'])\n\n    def attr_matches(self, text):\n        # Borrowed from IPython's completer\n        m = re.match(r\"(\\S+(\\.[\\w-]+)*)\\.([\\w-]*)$\", text)\n\n        if m:\n            expr, attr = m.group(1, 3)\n            attr = attr.replace(\"-\", \"_\")\n            expr = expr.replace(\"-\", \"_\")\n        else:\n            return []\n\n        try:\n            obj = eval(expr, self.namespace)\n            words = dir(obj)\n        except Exception:\n            return []\n\n        n = len(attr)\n        matches = []\n        for w in words:\n            if w[:n] == attr:\n                matches.append(\"{}.{}\".format(\n                    expr.replace(\"_\", \"-\"), w.replace(\"_\", \"-\")))\n        return matches\n\n    def global_matches(self, text):\n        matches = []\n        for p in self.path:\n            for k in p.keys():\n                if isinstance(k, str):\n                    k = k.replace(\"_\", \"-\")\n                    if k.startswith(text):\n                        matches.append(k)\n        return matches\n\n    def tag_matches(self, text):\n        text = text[1:]\n        matches = []\n        for p in self.tag_path:\n            for k in p.keys():\n                if isinstance(k, str):\n                    if k.startswith(text):\n                        matches.append(\"#{}\".format(k))\n        return matches\n\n    def complete(self, text, state):\n        if text.startswith(\"#\"):\n            matches = self.tag_matches(text)\n        elif \".\" in text:\n            matches = self.attr_matches(text)\n        else:\n            matches = self.global_matches(text)\n        try:\n            return matches[state]\n        except IndexError:\n            return None\n\n\n@contextlib.contextmanager\ndef completion(completer=None):\n    delims = \"()[]{} \"\n    if not completer:\n        completer = Completer()\n\n    if docomplete:\n        readline.set_completer(completer.complete)\n        readline.set_completer_delims(delims)\n\n        history = os.path.expanduser(\"~/.hy-history\")\n        readline.parse_and_bind(\"set blink-matching-paren on\")\n\n        try:\n            readline.read_history_file(history)\n        except IOError:\n            open(history, 'a').close()\n\n        readline.parse_and_bind(readline_bind)\n\n    try:\n        yield\n    finally:\n        if docomplete:\n            readline.write_history_file(history)\n", "path": "hy/completer.py"}], "after_files": [{"content": "# Copyright 2019 the authors.\n# This file is part of Hy, which is free software licensed under the Expat\n# license. See the LICENSE.\n\nimport contextlib\nimport os\nimport re\nimport sys\nimport builtins\n\nimport hy.macros\nimport hy.compiler\n\n\ndocomplete = True\n\ntry:\n    import readline\nexcept ImportError:\n    try:\n        import pyreadline.rlmain\n        import pyreadline.unicode_helper  # NOQA\n        import readline\n    except ImportError:\n        docomplete = False\n\nif docomplete:\n    if sys.platform == 'darwin' and 'libedit' in readline.__doc__:\n        readline_bind = \"bind ^I rl_complete\"\n    else:\n        readline_bind = \"tab: complete\"\n\n\nclass Completer(object):\n\n    def __init__(self, namespace={}):\n        if not isinstance(namespace, dict):\n            raise TypeError('namespace must be a dictionary')\n        self.namespace = namespace\n        self.path = [hy.compiler._special_form_compilers,\n                     builtins.__dict__,\n                     namespace]\n\n        self.tag_path = []\n\n        namespace.setdefault('__macros__', {})\n        namespace.setdefault('__tags__', {})\n\n        self.path.append(namespace['__macros__'])\n        self.tag_path.append(namespace['__tags__'])\n\n    def attr_matches(self, text):\n        # Borrowed from IPython's completer\n        m = re.match(r\"(\\S+(\\.[\\w-]+)*)\\.([\\w-]*)$\", text)\n\n        if m:\n            expr, attr = m.group(1, 3)\n            attr = attr.replace(\"-\", \"_\")\n            expr = expr.replace(\"-\", \"_\")\n        else:\n            return []\n\n        try:\n            obj = eval(expr, self.namespace)\n            words = dir(obj)\n        except Exception:\n            return []\n\n        n = len(attr)\n        matches = []\n        for w in words:\n            if w[:n] == attr:\n                matches.append(\"{}.{}\".format(\n                    expr.replace(\"_\", \"-\"), w.replace(\"_\", \"-\")))\n        return matches\n\n    def global_matches(self, text):\n        matches = []\n        for p in self.path:\n            for k in p.keys():\n                if isinstance(k, str):\n                    k = k.replace(\"_\", \"-\")\n                    if k.startswith(text):\n                        matches.append(k)\n        return matches\n\n    def tag_matches(self, text):\n        text = text[1:]\n        matches = []\n        for p in self.tag_path:\n            for k in p.keys():\n                if isinstance(k, str):\n                    if k.startswith(text):\n                        matches.append(\"#{}\".format(k))\n        return matches\n\n    def complete(self, text, state):\n        if text.startswith(\"#\"):\n            matches = self.tag_matches(text)\n        elif \".\" in text:\n            matches = self.attr_matches(text)\n        else:\n            matches = self.global_matches(text)\n        try:\n            return matches[state]\n        except IndexError:\n            return None\n\n\n@contextlib.contextmanager\ndef completion(completer=None):\n    delims = \"()[]{} \"\n    if not completer:\n        completer = Completer()\n\n    if docomplete:\n        readline.set_completer(completer.complete)\n        readline.set_completer_delims(delims)\n\n        history = os.path.expanduser(\"~/.hy-history\")\n        readline.parse_and_bind(\"set blink-matching-paren on\")\n\n        try:\n            readline.read_history_file(history)\n        except IOError:\n            pass\n\n        readline.parse_and_bind(readline_bind)\n\n    try:\n        yield\n    finally:\n        if docomplete:\n            try:\n                readline.write_history_file(history)\n            except IOError:\n                pass\n", "path": "hy/completer.py"}]}