We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Access to socket information when using AppRunner
## Long story short

Sometimes I like to listen on port 0 to allow for any and need to access the actual port after binding.

## Expected behaviour

A public way to access socket information like the port number.

## Actual behaviour

I have to reach into the private `TCPSite._server`.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `aiohttp/web_runner.py`
Content:
```
1 import asyncio
2 import signal
3 import socket
4 from abc import ABC, abstractmethod
5 
6 from yarl import URL
7 
8 from .web_app import Application
9 
10 
11 __all__ = ('TCPSite', 'UnixSite', 'SockSite', 'BaseRunner',
12            'AppRunner', 'ServerRunner', 'GracefulExit')
13 
14 
15 class GracefulExit(SystemExit):
16     code = 1
17 
18 
19 def _raise_graceful_exit():
20     raise GracefulExit()
21 
22 
23 class BaseSite(ABC):
24     __slots__ = ('_runner', '_shutdown_timeout', '_ssl_context', '_backlog',
25                  '_server')
26 
27     def __init__(self, runner, *,
28                  shutdown_timeout=60.0, ssl_context=None,
29                  backlog=128):
30         if runner.server is None:
31             raise RuntimeError("Call runner.setup() before making a site")
32         self._runner = runner
33         self._shutdown_timeout = shutdown_timeout
34         self._ssl_context = ssl_context
35         self._backlog = backlog
36         self._server = None
37 
38     @property
39     @abstractmethod
40     def name(self):
41         pass  # pragma: no cover
42 
43     @abstractmethod
44     async def start(self):
45         self._runner._reg_site(self)
46 
47     async def stop(self):
48         self._runner._check_site(self)
49         if self._server is None:
50             self._runner._unreg_site(self)
51             return  # not started yet
52         self._server.close()
53         await self._server.wait_closed()
54         await self._runner.shutdown()
55         await self._runner.server.shutdown(self._shutdown_timeout)
56         self._runner._unreg_site(self)
57 
58 
59 class TCPSite(BaseSite):
60     __slots__ = ('_host', '_port', '_reuse_address', '_reuse_port')
61 
62     def __init__(self, runner, host=None, port=None, *,
63                  shutdown_timeout=60.0, ssl_context=None,
64                  backlog=128, reuse_address=None,
65                  reuse_port=None):
66         super().__init__(runner, shutdown_timeout=shutdown_timeout,
67                          ssl_context=ssl_context, backlog=backlog)
68         if host is None:
69             host = "0.0.0.0"
70         self._host = host
71         if port is None:
72             port = 8443 if self._ssl_context else 8080
73         self._port = port
74         self._reuse_address = reuse_address
75         self._reuse_port = reuse_port
76 
77     @property
78     def name(self):
79         scheme = 'https' if self._ssl_context else 'http'
80         return str(URL.build(scheme=scheme, host=self._host, port=self._port))
81 
82     async def start(self):
83         await super().start()
84         loop = asyncio.get_event_loop()
85         self._server = await loop.create_server(
86             self._runner.server, self._host, self._port,
87             ssl=self._ssl_context, backlog=self._backlog,
88             reuse_address=self._reuse_address,
89             reuse_port=self._reuse_port)
90 
91 
92 class UnixSite(BaseSite):
93     __slots__ = ('_path', )
94 
95     def __init__(self, runner, path, *,
96                  shutdown_timeout=60.0, ssl_context=None,
97                  backlog=128):
98         super().__init__(runner, shutdown_timeout=shutdown_timeout,
99                          ssl_context=ssl_context, backlog=backlog)
100         self._path = path
101 
102     @property
103     def name(self):
104         scheme = 'https' if self._ssl_context else 'http'
105         return '{}://unix:{}:'.format(scheme, self._path)
106 
107     async def start(self):
108         await super().start()
109         loop = asyncio.get_event_loop()
110         self._server = await loop.create_unix_server(
111             self._runner.server, self._path,
112             ssl=self._ssl_context, backlog=self._backlog)
113 
114 
115 class SockSite(BaseSite):
116     __slots__ = ('_sock', '_name')
117 
118     def __init__(self, runner, sock, *,
119                  shutdown_timeout=60.0, ssl_context=None,
120                  backlog=128):
121         super().__init__(runner, shutdown_timeout=shutdown_timeout,
122                          ssl_context=ssl_context, backlog=backlog)
123         self._sock = sock
124         scheme = 'https' if self._ssl_context else 'http'
125         if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:
126             name = '{}://unix:{}:'.format(scheme, sock.getsockname())
127         else:
128             host, port = sock.getsockname()[:2]
129             name = str(URL.build(scheme=scheme, host=host, port=port))
130         self._name = name
131 
132     @property
133     def name(self):
134         return self._name
135 
136     async def start(self):
137         await super().start()
138         loop = asyncio.get_event_loop()
139         self._server = await loop.create_server(
140             self._runner.server, sock=self._sock,
141             ssl=self._ssl_context, backlog=self._backlog)
142 
143 
144 class BaseRunner(ABC):
145     __slots__ = ('_handle_signals', '_kwargs', '_server', '_sites')
146 
147     def __init__(self, *, handle_signals=False, **kwargs):
148         self._handle_signals = handle_signals
149         self._kwargs = kwargs
150         self._server = None
151         self._sites = set()
152 
153     @property
154     def server(self):
155         return self._server
156 
157     @property
158     def sites(self):
159         return set(self._sites)
160 
161     async def setup(self):
162         loop = asyncio.get_event_loop()
163 
164         if self._handle_signals:
165             try:
166                 loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit)
167                 loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit)
168             except NotImplementedError:  # pragma: no cover
169                 # add_signal_handler is not implemented on Windows
170                 pass
171 
172         self._server = await self._make_server()
173 
174     @abstractmethod
175     async def shutdown(self):
176         pass  # pragma: no cover
177 
178     async def cleanup(self):
179         loop = asyncio.get_event_loop()
180 
181         if self._server is None:
182             # no started yet, do nothing
183             return
184 
185         # The loop over sites is intentional, an exception on gather()
186         # leaves self._sites in unpredictable state.
187         # The loop guaranties that a site is either deleted on success or
188         # still present on failure
189         for site in list(self._sites):
190             await site.stop()
191         await self._cleanup_server()
192         self._server = None
193         if self._handle_signals:
194             try:
195                 loop.remove_signal_handler(signal.SIGINT)
196                 loop.remove_signal_handler(signal.SIGTERM)
197             except NotImplementedError:  # pragma: no cover
198                 # remove_signal_handler is not implemented on Windows
199                 pass
200 
201     @abstractmethod
202     async def _make_server(self):
203         pass  # pragma: no cover
204 
205     @abstractmethod
206     async def _cleanup_server(self):
207         pass  # pragma: no cover
208 
209     def _reg_site(self, site):
210         if site in self._sites:
211             raise RuntimeError("Site {} is already registered in runner {}"
212                                .format(site, self))
213         self._sites.add(site)
214 
215     def _check_site(self, site):
216         if site not in self._sites:
217             raise RuntimeError("Site {} is not registered in runner {}"
218                                .format(site, self))
219 
220     def _unreg_site(self, site):
221         if site not in self._sites:
222             raise RuntimeError("Site {} is not registered in runner {}"
223                                .format(site, self))
224         self._sites.remove(site)
225 
226 
227 class ServerRunner(BaseRunner):
228     """Low-level web server runner"""
229 
230     __slots__ = ('_web_server',)
231 
232     def __init__(self, web_server, *, handle_signals=False, **kwargs):
233         super().__init__(handle_signals=handle_signals, **kwargs)
234         self._web_server = web_server
235 
236     async def shutdown(self):
237         pass
238 
239     async def _make_server(self):
240         return self._web_server
241 
242     async def _cleanup_server(self):
243         pass
244 
245 
246 class AppRunner(BaseRunner):
247     """Web Application runner"""
248 
249     __slots__ = ('_app',)
250 
251     def __init__(self, app, *, handle_signals=False, **kwargs):
252         super().__init__(handle_signals=handle_signals, **kwargs)
253         if not isinstance(app, Application):
254             raise TypeError("The first argument should be web.Application "
255                             "instance, got {!r}".format(app))
256         self._app = app
257 
258     @property
259     def app(self):
260         return self._app
261 
262     async def shutdown(self):
263         await self._app.shutdown()
264 
265     async def _make_server(self):
266         loop = asyncio.get_event_loop()
267         self._app._set_loop(loop)
268         self._app.on_startup.freeze()
269         await self._app.startup()
270         self._app.freeze()
271 
272         return self._app._make_handler(loop=loop, **self._kwargs)
273 
274     async def _cleanup_server(self):
275         await self._app.cleanup()
276
```
--- 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/aiohttp/web_runner.py b/aiohttp/web_runner.py
--- a/aiohttp/web_runner.py
+++ b/aiohttp/web_runner.py
@@ -148,12 +148,18 @@
         self._handle_signals = handle_signals
         self._kwargs = kwargs
         self._server = None
-        self._sites = set()
+        self._sites = []
 
     @property
     def server(self):
         return self._server
 
+    @property
+    def addresses(self):
+        return [sock.getsockname()
+                for site in self._sites
+                for sock in site._server.sockets]
+
     @property
     def sites(self):
         return set(self._sites)
@@ -210,7 +216,7 @@
         if site in self._sites:
             raise RuntimeError("Site {} is already registered in runner {}"
                                .format(site, self))
-        self._sites.add(site)
+        self._sites.append(site)
 
     def _check_site(self, site):
         if site not in self._sites:

{"golden_diff": "diff --git a/aiohttp/web_runner.py b/aiohttp/web_runner.py\n--- a/aiohttp/web_runner.py\n+++ b/aiohttp/web_runner.py\n@@ -148,12 +148,18 @@\n         self._handle_signals = handle_signals\n         self._kwargs = kwargs\n         self._server = None\n-        self._sites = set()\n+        self._sites = []\n \n     @property\n     def server(self):\n         return self._server\n \n+    @property\n+    def addresses(self):\n+        return [sock.getsockname()\n+                for site in self._sites\n+                for sock in site._server.sockets]\n+\n     @property\n     def sites(self):\n         return set(self._sites)\n@@ -210,7 +216,7 @@\n         if site in self._sites:\n             raise RuntimeError(\"Site {} is already registered in runner {}\"\n                                .format(site, self))\n-        self._sites.add(site)\n+        self._sites.append(site)\n \n     def _check_site(self, site):\n         if site not in self._sites:\n", "issue": "Access to socket information when using AppRunner\n## Long story short\r\n\r\nSometimes I like to listen on port 0 to allow for any and need to access the actual port after binding.\r\n\r\n## Expected behaviour\r\n\r\nA public way to access socket information like the port number.\r\n\r\n## Actual behaviour\r\n\r\nI have to reach into the private `TCPSite._server`.\n", "before_files": [{"content": "import asyncio\nimport signal\nimport socket\nfrom abc import ABC, abstractmethod\n\nfrom yarl import URL\n\nfrom .web_app import Application\n\n\n__all__ = ('TCPSite', 'UnixSite', 'SockSite', 'BaseRunner',\n           'AppRunner', 'ServerRunner', 'GracefulExit')\n\n\nclass GracefulExit(SystemExit):\n    code = 1\n\n\ndef _raise_graceful_exit():\n    raise GracefulExit()\n\n\nclass BaseSite(ABC):\n    __slots__ = ('_runner', '_shutdown_timeout', '_ssl_context', '_backlog',\n                 '_server')\n\n    def __init__(self, runner, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128):\n        if runner.server is None:\n            raise RuntimeError(\"Call runner.setup() before making a site\")\n        self._runner = runner\n        self._shutdown_timeout = shutdown_timeout\n        self._ssl_context = ssl_context\n        self._backlog = backlog\n        self._server = None\n\n    @property\n    @abstractmethod\n    def name(self):\n        pass  # pragma: no cover\n\n    @abstractmethod\n    async def start(self):\n        self._runner._reg_site(self)\n\n    async def stop(self):\n        self._runner._check_site(self)\n        if self._server is None:\n            self._runner._unreg_site(self)\n            return  # not started yet\n        self._server.close()\n        await self._server.wait_closed()\n        await self._runner.shutdown()\n        await self._runner.server.shutdown(self._shutdown_timeout)\n        self._runner._unreg_site(self)\n\n\nclass TCPSite(BaseSite):\n    __slots__ = ('_host', '_port', '_reuse_address', '_reuse_port')\n\n    def __init__(self, runner, host=None, port=None, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128, reuse_address=None,\n                 reuse_port=None):\n        super().__init__(runner, shutdown_timeout=shutdown_timeout,\n                         ssl_context=ssl_context, backlog=backlog)\n        if host is None:\n            host = \"0.0.0.0\"\n        self._host = host\n        if port is None:\n            port = 8443 if self._ssl_context else 8080\n        self._port = port\n        self._reuse_address = reuse_address\n        self._reuse_port = reuse_port\n\n    @property\n    def name(self):\n        scheme = 'https' if self._ssl_context else 'http'\n        return str(URL.build(scheme=scheme, host=self._host, port=self._port))\n\n    async def start(self):\n        await super().start()\n        loop = asyncio.get_event_loop()\n        self._server = await loop.create_server(\n            self._runner.server, self._host, self._port,\n            ssl=self._ssl_context, backlog=self._backlog,\n            reuse_address=self._reuse_address,\n            reuse_port=self._reuse_port)\n\n\nclass UnixSite(BaseSite):\n    __slots__ = ('_path', )\n\n    def __init__(self, runner, path, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128):\n        super().__init__(runner, shutdown_timeout=shutdown_timeout,\n                         ssl_context=ssl_context, backlog=backlog)\n        self._path = path\n\n    @property\n    def name(self):\n        scheme = 'https' if self._ssl_context else 'http'\n        return '{}://unix:{}:'.format(scheme, self._path)\n\n    async def start(self):\n        await super().start()\n        loop = asyncio.get_event_loop()\n        self._server = await loop.create_unix_server(\n            self._runner.server, self._path,\n            ssl=self._ssl_context, backlog=self._backlog)\n\n\nclass SockSite(BaseSite):\n    __slots__ = ('_sock', '_name')\n\n    def __init__(self, runner, sock, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128):\n        super().__init__(runner, shutdown_timeout=shutdown_timeout,\n                         ssl_context=ssl_context, backlog=backlog)\n        self._sock = sock\n        scheme = 'https' if self._ssl_context else 'http'\n        if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:\n            name = '{}://unix:{}:'.format(scheme, sock.getsockname())\n        else:\n            host, port = sock.getsockname()[:2]\n            name = str(URL.build(scheme=scheme, host=host, port=port))\n        self._name = name\n\n    @property\n    def name(self):\n        return self._name\n\n    async def start(self):\n        await super().start()\n        loop = asyncio.get_event_loop()\n        self._server = await loop.create_server(\n            self._runner.server, sock=self._sock,\n            ssl=self._ssl_context, backlog=self._backlog)\n\n\nclass BaseRunner(ABC):\n    __slots__ = ('_handle_signals', '_kwargs', '_server', '_sites')\n\n    def __init__(self, *, handle_signals=False, **kwargs):\n        self._handle_signals = handle_signals\n        self._kwargs = kwargs\n        self._server = None\n        self._sites = set()\n\n    @property\n    def server(self):\n        return self._server\n\n    @property\n    def sites(self):\n        return set(self._sites)\n\n    async def setup(self):\n        loop = asyncio.get_event_loop()\n\n        if self._handle_signals:\n            try:\n                loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit)\n                loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit)\n            except NotImplementedError:  # pragma: no cover\n                # add_signal_handler is not implemented on Windows\n                pass\n\n        self._server = await self._make_server()\n\n    @abstractmethod\n    async def shutdown(self):\n        pass  # pragma: no cover\n\n    async def cleanup(self):\n        loop = asyncio.get_event_loop()\n\n        if self._server is None:\n            # no started yet, do nothing\n            return\n\n        # The loop over sites is intentional, an exception on gather()\n        # leaves self._sites in unpredictable state.\n        # The loop guaranties that a site is either deleted on success or\n        # still present on failure\n        for site in list(self._sites):\n            await site.stop()\n        await self._cleanup_server()\n        self._server = None\n        if self._handle_signals:\n            try:\n                loop.remove_signal_handler(signal.SIGINT)\n                loop.remove_signal_handler(signal.SIGTERM)\n            except NotImplementedError:  # pragma: no cover\n                # remove_signal_handler is not implemented on Windows\n                pass\n\n    @abstractmethod\n    async def _make_server(self):\n        pass  # pragma: no cover\n\n    @abstractmethod\n    async def _cleanup_server(self):\n        pass  # pragma: no cover\n\n    def _reg_site(self, site):\n        if site in self._sites:\n            raise RuntimeError(\"Site {} is already registered in runner {}\"\n                               .format(site, self))\n        self._sites.add(site)\n\n    def _check_site(self, site):\n        if site not in self._sites:\n            raise RuntimeError(\"Site {} is not registered in runner {}\"\n                               .format(site, self))\n\n    def _unreg_site(self, site):\n        if site not in self._sites:\n            raise RuntimeError(\"Site {} is not registered in runner {}\"\n                               .format(site, self))\n        self._sites.remove(site)\n\n\nclass ServerRunner(BaseRunner):\n    \"\"\"Low-level web server runner\"\"\"\n\n    __slots__ = ('_web_server',)\n\n    def __init__(self, web_server, *, handle_signals=False, **kwargs):\n        super().__init__(handle_signals=handle_signals, **kwargs)\n        self._web_server = web_server\n\n    async def shutdown(self):\n        pass\n\n    async def _make_server(self):\n        return self._web_server\n\n    async def _cleanup_server(self):\n        pass\n\n\nclass AppRunner(BaseRunner):\n    \"\"\"Web Application runner\"\"\"\n\n    __slots__ = ('_app',)\n\n    def __init__(self, app, *, handle_signals=False, **kwargs):\n        super().__init__(handle_signals=handle_signals, **kwargs)\n        if not isinstance(app, Application):\n            raise TypeError(\"The first argument should be web.Application \"\n                            \"instance, got {!r}\".format(app))\n        self._app = app\n\n    @property\n    def app(self):\n        return self._app\n\n    async def shutdown(self):\n        await self._app.shutdown()\n\n    async def _make_server(self):\n        loop = asyncio.get_event_loop()\n        self._app._set_loop(loop)\n        self._app.on_startup.freeze()\n        await self._app.startup()\n        self._app.freeze()\n\n        return self._app._make_handler(loop=loop, **self._kwargs)\n\n    async def _cleanup_server(self):\n        await self._app.cleanup()\n", "path": "aiohttp/web_runner.py"}], "after_files": [{"content": "import asyncio\nimport signal\nimport socket\nfrom abc import ABC, abstractmethod\n\nfrom yarl import URL\n\nfrom .web_app import Application\n\n\n__all__ = ('TCPSite', 'UnixSite', 'SockSite', 'BaseRunner',\n           'AppRunner', 'ServerRunner', 'GracefulExit')\n\n\nclass GracefulExit(SystemExit):\n    code = 1\n\n\ndef _raise_graceful_exit():\n    raise GracefulExit()\n\n\nclass BaseSite(ABC):\n    __slots__ = ('_runner', '_shutdown_timeout', '_ssl_context', '_backlog',\n                 '_server')\n\n    def __init__(self, runner, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128):\n        if runner.server is None:\n            raise RuntimeError(\"Call runner.setup() before making a site\")\n        self._runner = runner\n        self._shutdown_timeout = shutdown_timeout\n        self._ssl_context = ssl_context\n        self._backlog = backlog\n        self._server = None\n\n    @property\n    @abstractmethod\n    def name(self):\n        pass  # pragma: no cover\n\n    @abstractmethod\n    async def start(self):\n        self._runner._reg_site(self)\n\n    async def stop(self):\n        self._runner._check_site(self)\n        if self._server is None:\n            self._runner._unreg_site(self)\n            return  # not started yet\n        self._server.close()\n        await self._server.wait_closed()\n        await self._runner.shutdown()\n        await self._runner.server.shutdown(self._shutdown_timeout)\n        self._runner._unreg_site(self)\n\n\nclass TCPSite(BaseSite):\n    __slots__ = ('_host', '_port', '_reuse_address', '_reuse_port')\n\n    def __init__(self, runner, host=None, port=None, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128, reuse_address=None,\n                 reuse_port=None):\n        super().__init__(runner, shutdown_timeout=shutdown_timeout,\n                         ssl_context=ssl_context, backlog=backlog)\n        if host is None:\n            host = \"0.0.0.0\"\n        self._host = host\n        if port is None:\n            port = 8443 if self._ssl_context else 8080\n        self._port = port\n        self._reuse_address = reuse_address\n        self._reuse_port = reuse_port\n\n    @property\n    def name(self):\n        scheme = 'https' if self._ssl_context else 'http'\n        return str(URL.build(scheme=scheme, host=self._host, port=self._port))\n\n    async def start(self):\n        await super().start()\n        loop = asyncio.get_event_loop()\n        self._server = await loop.create_server(\n            self._runner.server, self._host, self._port,\n            ssl=self._ssl_context, backlog=self._backlog,\n            reuse_address=self._reuse_address,\n            reuse_port=self._reuse_port)\n\n\nclass UnixSite(BaseSite):\n    __slots__ = ('_path', )\n\n    def __init__(self, runner, path, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128):\n        super().__init__(runner, shutdown_timeout=shutdown_timeout,\n                         ssl_context=ssl_context, backlog=backlog)\n        self._path = path\n\n    @property\n    def name(self):\n        scheme = 'https' if self._ssl_context else 'http'\n        return '{}://unix:{}:'.format(scheme, self._path)\n\n    async def start(self):\n        await super().start()\n        loop = asyncio.get_event_loop()\n        self._server = await loop.create_unix_server(\n            self._runner.server, self._path,\n            ssl=self._ssl_context, backlog=self._backlog)\n\n\nclass SockSite(BaseSite):\n    __slots__ = ('_sock', '_name')\n\n    def __init__(self, runner, sock, *,\n                 shutdown_timeout=60.0, ssl_context=None,\n                 backlog=128):\n        super().__init__(runner, shutdown_timeout=shutdown_timeout,\n                         ssl_context=ssl_context, backlog=backlog)\n        self._sock = sock\n        scheme = 'https' if self._ssl_context else 'http'\n        if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:\n            name = '{}://unix:{}:'.format(scheme, sock.getsockname())\n        else:\n            host, port = sock.getsockname()[:2]\n            name = str(URL.build(scheme=scheme, host=host, port=port))\n        self._name = name\n\n    @property\n    def name(self):\n        return self._name\n\n    async def start(self):\n        await super().start()\n        loop = asyncio.get_event_loop()\n        self._server = await loop.create_server(\n            self._runner.server, sock=self._sock,\n            ssl=self._ssl_context, backlog=self._backlog)\n\n\nclass BaseRunner(ABC):\n    __slots__ = ('_handle_signals', '_kwargs', '_server', '_sites')\n\n    def __init__(self, *, handle_signals=False, **kwargs):\n        self._handle_signals = handle_signals\n        self._kwargs = kwargs\n        self._server = None\n        self._sites = []\n\n    @property\n    def server(self):\n        return self._server\n\n    @property\n    def addresses(self):\n        return [sock.getsockname()\n                for site in self._sites\n                for sock in site._server.sockets]\n\n    @property\n    def sites(self):\n        return set(self._sites)\n\n    async def setup(self):\n        loop = asyncio.get_event_loop()\n\n        if self._handle_signals:\n            try:\n                loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit)\n                loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit)\n            except NotImplementedError:  # pragma: no cover\n                # add_signal_handler is not implemented on Windows\n                pass\n\n        self._server = await self._make_server()\n\n    @abstractmethod\n    async def shutdown(self):\n        pass  # pragma: no cover\n\n    async def cleanup(self):\n        loop = asyncio.get_event_loop()\n\n        if self._server is None:\n            # no started yet, do nothing\n            return\n\n        # The loop over sites is intentional, an exception on gather()\n        # leaves self._sites in unpredictable state.\n        # The loop guaranties that a site is either deleted on success or\n        # still present on failure\n        for site in list(self._sites):\n            await site.stop()\n        await self._cleanup_server()\n        self._server = None\n        if self._handle_signals:\n            try:\n                loop.remove_signal_handler(signal.SIGINT)\n                loop.remove_signal_handler(signal.SIGTERM)\n            except NotImplementedError:  # pragma: no cover\n                # remove_signal_handler is not implemented on Windows\n                pass\n\n    @abstractmethod\n    async def _make_server(self):\n        pass  # pragma: no cover\n\n    @abstractmethod\n    async def _cleanup_server(self):\n        pass  # pragma: no cover\n\n    def _reg_site(self, site):\n        if site in self._sites:\n            raise RuntimeError(\"Site {} is already registered in runner {}\"\n                               .format(site, self))\n        self._sites.append(site)\n\n    def _check_site(self, site):\n        if site not in self._sites:\n            raise RuntimeError(\"Site {} is not registered in runner {}\"\n                               .format(site, self))\n\n    def _unreg_site(self, site):\n        if site not in self._sites:\n            raise RuntimeError(\"Site {} is not registered in runner {}\"\n                               .format(site, self))\n        self._sites.remove(site)\n\n\nclass ServerRunner(BaseRunner):\n    \"\"\"Low-level web server runner\"\"\"\n\n    __slots__ = ('_web_server',)\n\n    def __init__(self, web_server, *, handle_signals=False, **kwargs):\n        super().__init__(handle_signals=handle_signals, **kwargs)\n        self._web_server = web_server\n\n    async def shutdown(self):\n        pass\n\n    async def _make_server(self):\n        return self._web_server\n\n    async def _cleanup_server(self):\n        pass\n\n\nclass AppRunner(BaseRunner):\n    \"\"\"Web Application runner\"\"\"\n\n    __slots__ = ('_app',)\n\n    def __init__(self, app, *, handle_signals=False, **kwargs):\n        super().__init__(handle_signals=handle_signals, **kwargs)\n        if not isinstance(app, Application):\n            raise TypeError(\"The first argument should be web.Application \"\n                            \"instance, got {!r}\".format(app))\n        self._app = app\n\n    @property\n    def app(self):\n        return self._app\n\n    async def shutdown(self):\n        await self._app.shutdown()\n\n    async def _make_server(self):\n        loop = asyncio.get_event_loop()\n        self._app._set_loop(loop)\n        self._app.on_startup.freeze()\n        await self._app.startup()\n        self._app.freeze()\n\n        return self._app._make_handler(loop=loop, **self._kwargs)\n\n    async def _cleanup_server(self):\n        await self._app.cleanup()\n", "path": "aiohttp/web_runner.py"}]}