prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  curses and SIGWINCH do not work properly with Hy.
  After importing curses under hy, curses is unable to detect the size of the terminal as it is resized.
  This manifests as curses.LINES and curses.COLS not being updated, stdscr.getmaxyx not working and so on.
  
  However, the workaround of launching the hy program from python with:
  ```
  import hy
  import curses
  from main import main_event_loop
  
  if __name__ == "__main__":
      curses.wrapper(main_event_loop, ...)
  ```
  allows curses to dynamically detect the size of the terminal.
  
  I conclude therefore the problem is with the hy binary. My (limited) understanding acquired during tracking down the source of this problem is that curses uses the SIGWINCH signal, so perhaps that is a place to look.
  
  Void linux x86 64bit, python 3.9.0
  Freebsd 12.2, python 3.8.6
  hy 0.19.0 (reported by pip) installed from git master branch via pip
  
  </issue>
  <code>
  [start of hy/completer.py]
  1 import contextlib
  2 import os
  3 import re
  4 import sys
  5 import builtins
  6 
  7 import hy.macros
  8 import hy.compiler
  9 
  10 
  11 docomplete = True
  12 
  13 try:
  14     import readline
  15 except AttributeError as e:
  16     # https://github.com/pyreadline/pyreadline/issues/65
  17     if "module 'collections' has no attribute 'Callable'" in str(e):
  18         docomplete = False
  19     else:
  20         raise
  21 except ImportError:
  22     docomplete = False
  23 
  24 if docomplete:
  25     if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
  26         readline_bind = "bind ^I rl_complete"
  27     else:
  28         readline_bind = "tab: complete"
  29 
  30 
  31 class Completer:
  32 
  33     def __init__(self, namespace={}):
  34         if not isinstance(namespace, dict):
  35             raise TypeError('namespace must be a dictionary')
  36         self.namespace = namespace
  37         self.path = [builtins.__dict__,
  38                      namespace]
  39 
  40         namespace.setdefault('__macros__', {})
  41 
  42         self.path.append(namespace['__macros__'])
  43 
  44     def attr_matches(self, text):
  45         # Borrowed from IPython's completer
  46         m = re.match(r"(\S+(\.[\w-]+)*)\.([\w-]*)$", text)
  47 
  48         if m:
  49             expr, attr = m.group(1, 3)
  50             attr = attr.replace("-", "_")
  51             expr = expr.replace("-", "_")
  52         else:
  53             return []
  54 
  55         try:
  56             obj = eval(expr, self.namespace)
  57             words = dir(obj)
  58         except Exception:
  59             return []
  60 
  61         n = len(attr)
  62         matches = []
  63         for w in words:
  64             if w[:n] == attr:
  65                 matches.append("{}.{}".format(
  66                     expr.replace("_", "-"), w.replace("_", "-")))
  67         return matches
  68 
  69     def global_matches(self, text):
  70         matches = []
  71         for p in self.path:
  72             for k in p.keys():
  73                 if isinstance(k, str):
  74                     k = k.replace("_", "-")
  75                     if k.startswith(text):
  76                         matches.append(k)
  77         return matches
  78 
  79     def complete(self, text, state):
  80         if "." in text:
  81             matches = self.attr_matches(text)
  82         else:
  83             matches = self.global_matches(text)
  84         try:
  85             return matches[state]
  86         except IndexError:
  87             return None
  88 
  89 
  90 @contextlib.contextmanager
  91 def completion(completer=None):
  92     delims = "()[]{} "
  93     if not completer:
  94         completer = Completer()
  95 
  96     if docomplete:
  97         readline.set_completer(completer.complete)
  98         readline.set_completer_delims(delims)
  99 
  100         history = os.environ.get(
  101             "HY_HISTORY", os.path.expanduser("~/.hy-history"))
  102         readline.parse_and_bind("set blink-matching-paren on")
  103 
  104         try:
  105             readline.read_history_file(history)
  106         except OSError:
  107             pass
  108 
  109         readline.parse_and_bind(readline_bind)
  110 
  111     try:
  112         yield
  113     finally:
  114         if docomplete:
  115             try:
  116                 readline.write_history_file(history)
  117             except OSError:
  118                 pass
  119
  [end of hy/completer.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/hy/completer.py b/hy/completer.py
  --- a/hy/completer.py
  +++ b/hy/completer.py
  @@ -8,24 +8,19 @@
   import hy.compiler
   
   
  -docomplete = True
  -
  -try:
  -    import readline
  -except AttributeError as e:
  -    # https://github.com/pyreadline/pyreadline/issues/65
  -    if "module 'collections' has no attribute 'Callable'" in str(e):
  -        docomplete = False
  -    else:
  -        raise
  -except ImportError:
  -    docomplete = False
  -
  -if docomplete:
  -    if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
  -        readline_bind = "bind ^I rl_complete"
  -    else:
  -        readline_bind = "tab: complete"
  +# Lazily import `readline` to work around
  +# https://bugs.python.org/issue2675#msg265564
  +readline = None
  +def init_readline():
  +    global readline
  +    try:
  +        import readline
  +    except AttributeError as e:
  +        # https://github.com/pyreadline/pyreadline/issues/65
  +        if "module 'collections' has no attribute 'Callable'" not in str(e):
  +            raise
  +    except ImportError:
  +        pass
   
   
   class Completer:
  @@ -86,33 +81,42 @@
           except IndexError:
               return None
   
  -
   @contextlib.contextmanager
   def completion(completer=None):
       delims = "()[]{} "
  +
  +    init_readline()
  +    if not readline:
  +        # We have nothing to do. Act like a null context manager.
  +        yield
  +        return
  +
       if not completer:
           completer = Completer()
   
  -    if docomplete:
  -        readline.set_completer(completer.complete)
  -        readline.set_completer_delims(delims)
  +    if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
  +        readline_bind = "bind ^I rl_complete"
  +    else:
  +        readline_bind = "tab: complete"
   
  -        history = os.environ.get(
  -            "HY_HISTORY", os.path.expanduser("~/.hy-history"))
  -        readline.parse_and_bind("set blink-matching-paren on")
  +    readline.set_completer(completer.complete)
  +    readline.set_completer_delims(delims)
   
  -        try:
  -            readline.read_history_file(history)
  -        except OSError:
  -            pass
  +    history = os.environ.get(
  +        "HY_HISTORY", os.path.expanduser("~/.hy-history"))
  +    readline.parse_and_bind("set blink-matching-paren on")
   
  -        readline.parse_and_bind(readline_bind)
  +    try:
  +        readline.read_history_file(history)
  +    except OSError:
  +        pass
  +
  +    readline.parse_and_bind(readline_bind)
   
       try:
           yield
       finally:
  -        if docomplete:
  -            try:
  -                readline.write_history_file(history)
  -            except OSError:
  -                pass
  +        try:
  +            readline.write_history_file(history)
  +        except OSError:
  +            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@@ -8,24 +8,19 @@\n import hy.compiler\n \n \n-docomplete = True\n-\n-try:\n-    import readline\n-except AttributeError as e:\n-    # https://github.com/pyreadline/pyreadline/issues/65\n-    if \"module 'collections' has no attribute 'Callable'\" in str(e):\n-        docomplete = False\n-    else:\n-        raise\n-except ImportError:\n-    docomplete = False\n-\n-if 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+# Lazily import `readline` to work around\n+# https://bugs.python.org/issue2675#msg265564\n+readline = None\n+def init_readline():\n+    global readline\n+    try:\n+        import readline\n+    except AttributeError as e:\n+        # https://github.com/pyreadline/pyreadline/issues/65\n+        if \"module 'collections' has no attribute 'Callable'\" not in str(e):\n+            raise\n+    except ImportError:\n+        pass\n \n \n class Completer:\n@@ -86,33 +81,42 @@\n         except IndexError:\n             return None\n \n-\n @contextlib.contextmanager\n def completion(completer=None):\n     delims = \"()[]{} \"\n+\n+    init_readline()\n+    if not readline:\n+        # We have nothing to do. Act like a null context manager.\n+        yield\n+        return\n+\n     if not completer:\n         completer = Completer()\n \n-    if docomplete:\n-        readline.set_completer(completer.complete)\n-        readline.set_completer_delims(delims)\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-        history = os.environ.get(\n-            \"HY_HISTORY\", os.path.expanduser(\"~/.hy-history\"))\n-        readline.parse_and_bind(\"set blink-matching-paren on\")\n+    readline.set_completer(completer.complete)\n+    readline.set_completer_delims(delims)\n \n-        try:\n-            readline.read_history_file(history)\n-        except OSError:\n-            pass\n+    history = os.environ.get(\n+        \"HY_HISTORY\", os.path.expanduser(\"~/.hy-history\"))\n+    readline.parse_and_bind(\"set blink-matching-paren on\")\n \n-        readline.parse_and_bind(readline_bind)\n+    try:\n+        readline.read_history_file(history)\n+    except OSError:\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 OSError:\n-                pass\n+        try:\n+            readline.write_history_file(history)\n+        except OSError:\n+            pass\n", "issue": "curses and SIGWINCH do not work properly with Hy.\nAfter importing curses under hy, curses is unable to detect the size of the terminal as it is resized.\r\nThis manifests as curses.LINES and curses.COLS not being updated, stdscr.getmaxyx not working and so on.\r\n\r\nHowever, the workaround of launching the hy program from python with:\r\n```\r\nimport hy\r\nimport curses\r\nfrom main import main_event_loop\r\n\r\nif __name__ == \"__main__\":\r\n    curses.wrapper(main_event_loop, ...)\r\n```\r\nallows curses to dynamically detect the size of the terminal.\r\n\r\nI conclude therefore the problem is with the hy binary. My (limited) understanding acquired during tracking down the source of this problem is that curses uses the SIGWINCH signal, so perhaps that is a place to look.\r\n\r\nVoid linux x86 64bit, python 3.9.0\r\nFreebsd 12.2, python 3.8.6\r\nhy 0.19.0 (reported by pip) installed from git master branch via pip\n", "before_files": [{"content": "import 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 AttributeError as e:\n    # https://github.com/pyreadline/pyreadline/issues/65\n    if \"module 'collections' has no attribute 'Callable'\" in str(e):\n        docomplete = False\n    else:\n        raise\nexcept 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:\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 = [builtins.__dict__,\n                     namespace]\n\n        namespace.setdefault('__macros__', {})\n\n        self.path.append(namespace['__macros__'])\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 complete(self, text, state):\n        if \".\" 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.environ.get(\n            \"HY_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 OSError:\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 OSError:\n                pass\n", "path": "hy/completer.py"}]}