We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
trio.open_signal_receiver should give an error if no arguments are passed
User confusion spotted in the wild: https://gitter.im/python-trio/general?at=5ebfa9d613878c30b581b9fe


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `trio/_signals.py`
Content:
```
1 import signal
2 from contextlib import contextmanager
3 from collections import OrderedDict
4 
5 import trio
6 from ._util import signal_raise, is_main_thread, ConflictDetector
7 
8 # Discussion of signal handling strategies:
9 #
10 # - On Windows signals barely exist. There are no options; signal handlers are
11 #   the only available API.
12 #
13 # - On Linux signalfd is arguably the natural way. Semantics: signalfd acts as
14 #   an *alternative* signal delivery mechanism. The way you use it is to mask
15 #   out the relevant signals process-wide (so that they don't get delivered
16 #   the normal way), and then when you read from signalfd that actually counts
17 #   as delivering it (despite the mask). The problem with this is that we
18 #   don't have any reliable way to mask out signals process-wide -- the only
19 #   way to do that in Python is to call pthread_sigmask from the main thread
20 #   *before starting any other threads*, and as a library we can't really
21 #   impose that, and the failure mode is annoying (signals get delivered via
22 #   signal handlers whether we want them to or not).
23 #
24 # - on macOS/*BSD, kqueue is the natural way. Semantics: kqueue acts as an
25 #   *extra* signal delivery mechanism. Signals are delivered the normal
26 #   way, *and* are delivered to kqueue. So you want to set them to SIG_IGN so
27 #   that they don't end up pending forever (I guess?). I can't find any actual
28 #   docs on how masking and EVFILT_SIGNAL interact. I did see someone note
29 #   that if a signal is pending when the kqueue filter is added then you
30 #   *don't* get notified of that, which makes sense. But still, we have to
31 #   manipulate signal state (e.g. setting SIG_IGN) which as far as Python is
32 #   concerned means we have to do this from the main thread.
33 #
34 # So in summary, there don't seem to be any compelling advantages to using the
35 # platform-native signal notification systems; they're kinda nice, but it's
36 # simpler to implement the naive signal-handler-based system once and be
37 # done. (The big advantage would be if there were a reliable way to monitor
38 # for SIGCHLD from outside the main thread and without interfering with other
39 # libraries that also want to monitor for SIGCHLD. But there isn't. I guess
40 # kqueue might give us that, but in kqueue we don't need it, because kqueue
41 # can directly monitor for child process state changes.)
42 
43 
44 @contextmanager
45 def _signal_handler(signals, handler):
46     original_handlers = {}
47     try:
48         for signum in set(signals):
49             original_handlers[signum] = signal.signal(signum, handler)
50         yield
51     finally:
52         for signum, original_handler in original_handlers.items():
53             signal.signal(signum, original_handler)
54 
55 
56 class SignalReceiver:
57     def __init__(self):
58         # {signal num: None}
59         self._pending = OrderedDict()
60         self._lot = trio.lowlevel.ParkingLot()
61         self._conflict_detector = ConflictDetector(
62             "only one task can iterate on a signal receiver at a time"
63         )
64         self._closed = False
65 
66     def _add(self, signum):
67         if self._closed:
68             signal_raise(signum)
69         else:
70             self._pending[signum] = None
71             self._lot.unpark()
72 
73     def _redeliver_remaining(self):
74         # First make sure that any signals still in the delivery pipeline will
75         # get redelivered
76         self._closed = True
77 
78         # And then redeliver any that are sitting in pending. This is done
79         # using a weird recursive construct to make sure we process everything
80         # even if some of the handlers raise exceptions.
81         def deliver_next():
82             if self._pending:
83                 signum, _ = self._pending.popitem(last=False)
84                 try:
85                     signal_raise(signum)
86                 finally:
87                     deliver_next()
88 
89         deliver_next()
90 
91     # Helper for tests, not public or otherwise used
92     def _pending_signal_count(self):
93         return len(self._pending)
94 
95     def __aiter__(self):
96         return self
97 
98     async def __anext__(self):
99         if self._closed:
100             raise RuntimeError("open_signal_receiver block already exited")
101         # In principle it would be possible to support multiple concurrent
102         # calls to __anext__, but doing it without race conditions is quite
103         # tricky, and there doesn't seem to be any point in trying.
104         with self._conflict_detector:
105             if not self._pending:
106                 await self._lot.park()
107             else:
108                 await trio.lowlevel.checkpoint()
109             signum, _ = self._pending.popitem(last=False)
110             return signum
111 
112 
113 @contextmanager
114 def open_signal_receiver(*signals):
115     """A context manager for catching signals.
116 
117     Entering this context manager starts listening for the given signals and
118     returns an async iterator; exiting the context manager stops listening.
119 
120     The async iterator blocks until a signal arrives, and then yields it.
121 
122     Note that if you leave the ``with`` block while the iterator has
123     unextracted signals still pending inside it, then they will be
124     re-delivered using Python's regular signal handling logic. This avoids a
125     race condition when signals arrives just before we exit the ``with``
126     block.
127 
128     Args:
129       signals: the signals to listen for.
130 
131     Raises:
132       RuntimeError: if you try to use this anywhere except Python's main
133           thread. (This is a Python limitation.)
134 
135     Example:
136 
137       A common convention for Unix daemons is that they should reload their
138       configuration when they receive a ``SIGHUP``. Here's a sketch of what
139       that might look like using :func:`open_signal_receiver`::
140 
141          with trio.open_signal_receiver(signal.SIGHUP) as signal_aiter:
142              async for signum in signal_aiter:
143                  assert signum == signal.SIGHUP
144                  reload_configuration()
145 
146     """
147     if not is_main_thread():
148         raise RuntimeError(
149             "Sorry, open_signal_receiver is only possible when running in "
150             "Python interpreter's main thread"
151         )
152     token = trio.lowlevel.current_trio_token()
153     queue = SignalReceiver()
154 
155     def handler(signum, _):
156         token.run_sync_soon(queue._add, signum, idempotent=True)
157 
158     try:
159         with _signal_handler(signals, handler):
160             yield queue
161     finally:
162         queue._redeliver_remaining()
163
```
--- 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()

```

diff --git a/trio/_signals.py b/trio/_signals.py
--- a/trio/_signals.py
+++ b/trio/_signals.py
@@ -129,6 +129,8 @@
       signals: the signals to listen for.
 
     Raises:
+      TypeError: if no signals were provided.
+
       RuntimeError: if you try to use this anywhere except Python's main
           thread. (This is a Python limitation.)
 
@@ -144,6 +146,9 @@
                  reload_configuration()
 
     """
+    if not signals:
+        raise TypeError("No signals were provided")
+
     if not is_main_thread():
         raise RuntimeError(
             "Sorry, open_signal_receiver is only possible when running in "

{"golden_diff": "diff --git a/trio/_signals.py b/trio/_signals.py\n--- a/trio/_signals.py\n+++ b/trio/_signals.py\n@@ -129,6 +129,8 @@\n       signals: the signals to listen for.\n \n     Raises:\n+      TypeError: if no signals were provided.\n+\n       RuntimeError: if you try to use this anywhere except Python's main\n           thread. (This is a Python limitation.)\n \n@@ -144,6 +146,9 @@\n                  reload_configuration()\n \n     \"\"\"\n+    if not signals:\n+        raise TypeError(\"No signals were provided\")\n+\n     if not is_main_thread():\n         raise RuntimeError(\n             \"Sorry, open_signal_receiver is only possible when running in \"\n", "issue": "trio.open_signal_receiver should give an error if no arguments are passed\nUser confusion spotted in the wild: https://gitter.im/python-trio/general?at=5ebfa9d613878c30b581b9fe\r\n\n", "before_files": [{"content": "import signal\nfrom contextlib import contextmanager\nfrom collections import OrderedDict\n\nimport trio\nfrom ._util import signal_raise, is_main_thread, ConflictDetector\n\n# Discussion of signal handling strategies:\n#\n# - On Windows signals barely exist. There are no options; signal handlers are\n#   the only available API.\n#\n# - On Linux signalfd is arguably the natural way. Semantics: signalfd acts as\n#   an *alternative* signal delivery mechanism. The way you use it is to mask\n#   out the relevant signals process-wide (so that they don't get delivered\n#   the normal way), and then when you read from signalfd that actually counts\n#   as delivering it (despite the mask). The problem with this is that we\n#   don't have any reliable way to mask out signals process-wide -- the only\n#   way to do that in Python is to call pthread_sigmask from the main thread\n#   *before starting any other threads*, and as a library we can't really\n#   impose that, and the failure mode is annoying (signals get delivered via\n#   signal handlers whether we want them to or not).\n#\n# - on macOS/*BSD, kqueue is the natural way. Semantics: kqueue acts as an\n#   *extra* signal delivery mechanism. Signals are delivered the normal\n#   way, *and* are delivered to kqueue. So you want to set them to SIG_IGN so\n#   that they don't end up pending forever (I guess?). I can't find any actual\n#   docs on how masking and EVFILT_SIGNAL interact. I did see someone note\n#   that if a signal is pending when the kqueue filter is added then you\n#   *don't* get notified of that, which makes sense. But still, we have to\n#   manipulate signal state (e.g. setting SIG_IGN) which as far as Python is\n#   concerned means we have to do this from the main thread.\n#\n# So in summary, there don't seem to be any compelling advantages to using the\n# platform-native signal notification systems; they're kinda nice, but it's\n# simpler to implement the naive signal-handler-based system once and be\n# done. (The big advantage would be if there were a reliable way to monitor\n# for SIGCHLD from outside the main thread and without interfering with other\n# libraries that also want to monitor for SIGCHLD. But there isn't. I guess\n# kqueue might give us that, but in kqueue we don't need it, because kqueue\n# can directly monitor for child process state changes.)\n\n\n@contextmanager\ndef _signal_handler(signals, handler):\n    original_handlers = {}\n    try:\n        for signum in set(signals):\n            original_handlers[signum] = signal.signal(signum, handler)\n        yield\n    finally:\n        for signum, original_handler in original_handlers.items():\n            signal.signal(signum, original_handler)\n\n\nclass SignalReceiver:\n    def __init__(self):\n        # {signal num: None}\n        self._pending = OrderedDict()\n        self._lot = trio.lowlevel.ParkingLot()\n        self._conflict_detector = ConflictDetector(\n            \"only one task can iterate on a signal receiver at a time\"\n        )\n        self._closed = False\n\n    def _add(self, signum):\n        if self._closed:\n            signal_raise(signum)\n        else:\n            self._pending[signum] = None\n            self._lot.unpark()\n\n    def _redeliver_remaining(self):\n        # First make sure that any signals still in the delivery pipeline will\n        # get redelivered\n        self._closed = True\n\n        # And then redeliver any that are sitting in pending. This is done\n        # using a weird recursive construct to make sure we process everything\n        # even if some of the handlers raise exceptions.\n        def deliver_next():\n            if self._pending:\n                signum, _ = self._pending.popitem(last=False)\n                try:\n                    signal_raise(signum)\n                finally:\n                    deliver_next()\n\n        deliver_next()\n\n    # Helper for tests, not public or otherwise used\n    def _pending_signal_count(self):\n        return len(self._pending)\n\n    def __aiter__(self):\n        return self\n\n    async def __anext__(self):\n        if self._closed:\n            raise RuntimeError(\"open_signal_receiver block already exited\")\n        # In principle it would be possible to support multiple concurrent\n        # calls to __anext__, but doing it without race conditions is quite\n        # tricky, and there doesn't seem to be any point in trying.\n        with self._conflict_detector:\n            if not self._pending:\n                await self._lot.park()\n            else:\n                await trio.lowlevel.checkpoint()\n            signum, _ = self._pending.popitem(last=False)\n            return signum\n\n\n@contextmanager\ndef open_signal_receiver(*signals):\n    \"\"\"A context manager for catching signals.\n\n    Entering this context manager starts listening for the given signals and\n    returns an async iterator; exiting the context manager stops listening.\n\n    The async iterator blocks until a signal arrives, and then yields it.\n\n    Note that if you leave the ``with`` block while the iterator has\n    unextracted signals still pending inside it, then they will be\n    re-delivered using Python's regular signal handling logic. This avoids a\n    race condition when signals arrives just before we exit the ``with``\n    block.\n\n    Args:\n      signals: the signals to listen for.\n\n    Raises:\n      RuntimeError: if you try to use this anywhere except Python's main\n          thread. (This is a Python limitation.)\n\n    Example:\n\n      A common convention for Unix daemons is that they should reload their\n      configuration when they receive a ``SIGHUP``. Here's a sketch of what\n      that might look like using :func:`open_signal_receiver`::\n\n         with trio.open_signal_receiver(signal.SIGHUP) as signal_aiter:\n             async for signum in signal_aiter:\n                 assert signum == signal.SIGHUP\n                 reload_configuration()\n\n    \"\"\"\n    if not is_main_thread():\n        raise RuntimeError(\n            \"Sorry, open_signal_receiver is only possible when running in \"\n            \"Python interpreter's main thread\"\n        )\n    token = trio.lowlevel.current_trio_token()\n    queue = SignalReceiver()\n\n    def handler(signum, _):\n        token.run_sync_soon(queue._add, signum, idempotent=True)\n\n    try:\n        with _signal_handler(signals, handler):\n            yield queue\n    finally:\n        queue._redeliver_remaining()\n", "path": "trio/_signals.py"}], "after_files": [{"content": "import signal\nfrom contextlib import contextmanager\nfrom collections import OrderedDict\n\nimport trio\nfrom ._util import signal_raise, is_main_thread, ConflictDetector\n\n# Discussion of signal handling strategies:\n#\n# - On Windows signals barely exist. There are no options; signal handlers are\n#   the only available API.\n#\n# - On Linux signalfd is arguably the natural way. Semantics: signalfd acts as\n#   an *alternative* signal delivery mechanism. The way you use it is to mask\n#   out the relevant signals process-wide (so that they don't get delivered\n#   the normal way), and then when you read from signalfd that actually counts\n#   as delivering it (despite the mask). The problem with this is that we\n#   don't have any reliable way to mask out signals process-wide -- the only\n#   way to do that in Python is to call pthread_sigmask from the main thread\n#   *before starting any other threads*, and as a library we can't really\n#   impose that, and the failure mode is annoying (signals get delivered via\n#   signal handlers whether we want them to or not).\n#\n# - on macOS/*BSD, kqueue is the natural way. Semantics: kqueue acts as an\n#   *extra* signal delivery mechanism. Signals are delivered the normal\n#   way, *and* are delivered to kqueue. So you want to set them to SIG_IGN so\n#   that they don't end up pending forever (I guess?). I can't find any actual\n#   docs on how masking and EVFILT_SIGNAL interact. I did see someone note\n#   that if a signal is pending when the kqueue filter is added then you\n#   *don't* get notified of that, which makes sense. But still, we have to\n#   manipulate signal state (e.g. setting SIG_IGN) which as far as Python is\n#   concerned means we have to do this from the main thread.\n#\n# So in summary, there don't seem to be any compelling advantages to using the\n# platform-native signal notification systems; they're kinda nice, but it's\n# simpler to implement the naive signal-handler-based system once and be\n# done. (The big advantage would be if there were a reliable way to monitor\n# for SIGCHLD from outside the main thread and without interfering with other\n# libraries that also want to monitor for SIGCHLD. But there isn't. I guess\n# kqueue might give us that, but in kqueue we don't need it, because kqueue\n# can directly monitor for child process state changes.)\n\n\n@contextmanager\ndef _signal_handler(signals, handler):\n    original_handlers = {}\n    try:\n        for signum in set(signals):\n            original_handlers[signum] = signal.signal(signum, handler)\n        yield\n    finally:\n        for signum, original_handler in original_handlers.items():\n            signal.signal(signum, original_handler)\n\n\nclass SignalReceiver:\n    def __init__(self):\n        # {signal num: None}\n        self._pending = OrderedDict()\n        self._lot = trio.lowlevel.ParkingLot()\n        self._conflict_detector = ConflictDetector(\n            \"only one task can iterate on a signal receiver at a time\"\n        )\n        self._closed = False\n\n    def _add(self, signum):\n        if self._closed:\n            signal_raise(signum)\n        else:\n            self._pending[signum] = None\n            self._lot.unpark()\n\n    def _redeliver_remaining(self):\n        # First make sure that any signals still in the delivery pipeline will\n        # get redelivered\n        self._closed = True\n\n        # And then redeliver any that are sitting in pending. This is done\n        # using a weird recursive construct to make sure we process everything\n        # even if some of the handlers raise exceptions.\n        def deliver_next():\n            if self._pending:\n                signum, _ = self._pending.popitem(last=False)\n                try:\n                    signal_raise(signum)\n                finally:\n                    deliver_next()\n\n        deliver_next()\n\n    # Helper for tests, not public or otherwise used\n    def _pending_signal_count(self):\n        return len(self._pending)\n\n    def __aiter__(self):\n        return self\n\n    async def __anext__(self):\n        if self._closed:\n            raise RuntimeError(\"open_signal_receiver block already exited\")\n        # In principle it would be possible to support multiple concurrent\n        # calls to __anext__, but doing it without race conditions is quite\n        # tricky, and there doesn't seem to be any point in trying.\n        with self._conflict_detector:\n            if not self._pending:\n                await self._lot.park()\n            else:\n                await trio.lowlevel.checkpoint()\n            signum, _ = self._pending.popitem(last=False)\n            return signum\n\n\n@contextmanager\ndef open_signal_receiver(*signals):\n    \"\"\"A context manager for catching signals.\n\n    Entering this context manager starts listening for the given signals and\n    returns an async iterator; exiting the context manager stops listening.\n\n    The async iterator blocks until a signal arrives, and then yields it.\n\n    Note that if you leave the ``with`` block while the iterator has\n    unextracted signals still pending inside it, then they will be\n    re-delivered using Python's regular signal handling logic. This avoids a\n    race condition when signals arrives just before we exit the ``with``\n    block.\n\n    Args:\n      signals: the signals to listen for.\n\n    Raises:\n      TypeError: if no signals were provided.\n\n      RuntimeError: if you try to use this anywhere except Python's main\n          thread. (This is a Python limitation.)\n\n    Example:\n\n      A common convention for Unix daemons is that they should reload their\n      configuration when they receive a ``SIGHUP``. Here's a sketch of what\n      that might look like using :func:`open_signal_receiver`::\n\n         with trio.open_signal_receiver(signal.SIGHUP) as signal_aiter:\n             async for signum in signal_aiter:\n                 assert signum == signal.SIGHUP\n                 reload_configuration()\n\n    \"\"\"\n    if not signals:\n        raise TypeError(\"No signals were provided\")\n\n    if not is_main_thread():\n        raise RuntimeError(\n            \"Sorry, open_signal_receiver is only possible when running in \"\n            \"Python interpreter's main thread\"\n        )\n    token = trio.lowlevel.current_trio_token()\n    queue = SignalReceiver()\n\n    def handler(signum, _):\n        token.run_sync_soon(queue._add, signum, idempotent=True)\n\n    try:\n        with _signal_handler(signals, handler):\n            yield queue\n    finally:\n        queue._redeliver_remaining()\n", "path": "trio/_signals.py"}]}