We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Deploying inside a process manager: must account for inherited socket family and type
Hi,

I get an error when trying to run uvicorn with Circus, but only if using a socket with file descriptor (which I'd like to do to increase the number of processes).

circus.ini:
```
[socket:web]
host = 0.0.0.0
port = 80
[watcher:uvicorn]
cmd = uvicorn
# args = --host 0.0.0.0 --port 80 satemo.asgi:application 
# --> works ok
args = --fd $(circus.sockets.web) satemo.asgi:application 
# --> Fails
use_sockets = True
numprocesses = 1
```

Error:
```
File "c:\nss\venv\channels2\lib\site-packages\uvicorn\main.py", line 247, in startup
    sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)
UnboundLocalError: local variable 'socket' referenced before assignment
```

Environment:
* Windows 10
* Python 3.6.5
* uvicorn 0.4.1


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `uvicorn/main.py`
Content:
```
1 import asyncio
2 import functools
3 import os
4 import signal
5 import sys
6 import time
7 from email.utils import formatdate
8 
9 import click
10 
11 from uvicorn.config import (
12     HTTP_PROTOCOLS,
13     LIFESPAN,
14     LOG_LEVELS,
15     LOOP_SETUPS,
16     WS_PROTOCOLS,
17     Config,
18     get_logger,
19 )
20 from uvicorn.reloaders.statreload import StatReload
21 
22 LEVEL_CHOICES = click.Choice(LOG_LEVELS.keys())
23 HTTP_CHOICES = click.Choice(HTTP_PROTOCOLS.keys())
24 WS_CHOICES = click.Choice(WS_PROTOCOLS.keys())
25 LIFESPAN_CHOICES = click.Choice(LIFESPAN.keys())
26 LOOP_CHOICES = click.Choice(LOOP_SETUPS.keys())
27 
28 HANDLED_SIGNALS = (
29     signal.SIGINT,  # Unix signal 2. Sent by Ctrl+C.
30     signal.SIGTERM,  # Unix signal 15. Sent by `kill <pid>`.
31 )
32 
33 
34 @click.command()
35 @click.argument("app")
36 @click.option(
37     "--host",
38     type=str,
39     default="127.0.0.1",
40     help="Bind socket to this host.",
41     show_default=True,
42 )
43 @click.option(
44     "--port",
45     type=int,
46     default=8000,
47     help="Bind socket to this port.",
48     show_default=True,
49 )
50 @click.option("--uds", type=str, default=None, help="Bind to a UNIX domain socket.")
51 @click.option(
52     "--fd", type=int, default=None, help="Bind to socket from this file descriptor."
53 )
54 @click.option(
55     "--loop",
56     type=LOOP_CHOICES,
57     default="auto",
58     help="Event loop implementation.",
59     show_default=True,
60 )
61 @click.option(
62     "--http",
63     type=HTTP_CHOICES,
64     default="auto",
65     help="HTTP protocol implementation.",
66     show_default=True,
67 )
68 @click.option(
69     "--ws",
70     type=WS_CHOICES,
71     default="auto",
72     help="WebSocket protocol implementation.",
73     show_default=True,
74 )
75 @click.option(
76     "--lifespan",
77     type=LIFESPAN_CHOICES,
78     default="auto",
79     help="Lifespan implementation.",
80     show_default=True,
81 )
82 @click.option(
83     "--wsgi",
84     is_flag=True,
85     default=False,
86     help="Use WSGI as the application interface, instead of ASGI.",
87 )
88 @click.option("--debug", is_flag=True, default=False, help="Enable debug mode.")
89 @click.option(
90     "--log-level",
91     type=LEVEL_CHOICES,
92     default="info",
93     help="Log level.",
94     show_default=True,
95 )
96 @click.option(
97     "--no-access-log", is_flag=True, default=False, help="Disable access log."
98 )
99 @click.option(
100     "--proxy-headers",
101     is_flag=True,
102     default=False,
103     help="Use X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info.",
104 )
105 @click.option(
106     "--root-path",
107     type=str,
108     default="",
109     help="Set the ASGI 'root_path' for applications submounted below a given URL path.",
110 )
111 @click.option(
112     "--limit-concurrency",
113     type=int,
114     default=None,
115     help="Maximum number of concurrent connections or tasks to allow, before issuing HTTP 503 responses.",
116 )
117 @click.option(
118     "--limit-max-requests",
119     type=int,
120     default=None,
121     help="Maximum number of requests to service before terminating the process.",
122 )
123 @click.option(
124     "--timeout-keep-alive",
125     type=int,
126     default=5,
127     help="Close Keep-Alive connections if no new data is received within this timeout.",
128     show_default=True,
129 )
130 def main(
131     app,
132     host: str,
133     port: int,
134     uds: str,
135     fd: int,
136     loop: str,
137     http: str,
138     ws: str,
139     lifespan: str,
140     wsgi: bool,
141     debug: bool,
142     log_level: str,
143     no_access_log: bool,
144     proxy_headers: bool,
145     root_path: str,
146     limit_concurrency: int,
147     limit_max_requests: int,
148     timeout_keep_alive: int,
149 ):
150     sys.path.insert(0, ".")
151 
152     kwargs = {
153         "app": app,
154         "host": host,
155         "port": port,
156         "uds": uds,
157         "fd": fd,
158         "loop": loop,
159         "http": http,
160         "ws": ws,
161         "lifespan": lifespan,
162         "log_level": log_level,
163         "access_log": not no_access_log,
164         "wsgi": wsgi,
165         "debug": debug,
166         "proxy_headers": proxy_headers,
167         "root_path": root_path,
168         "limit_concurrency": limit_concurrency,
169         "limit_max_requests": limit_max_requests,
170         "timeout_keep_alive": timeout_keep_alive,
171     }
172 
173     if debug:
174         logger = get_logger(log_level)
175         reloader = StatReload(logger)
176         reloader.run(run, kwargs)
177     else:
178         run(**kwargs)
179 
180 
181 def run(app, **kwargs):
182     config = Config(app, **kwargs)
183     server = Server(config=config)
184     server.run()
185 
186 
187 class ServerState:
188     """
189     Shared servers state that is available between all protocol instances.
190     """
191 
192     def __init__(self):
193         self.total_requests = 0
194         self.connections = set()
195         self.tasks = set()
196         self.default_headers = []
197 
198 
199 class Server:
200     def __init__(self, config):
201         self.config = config
202         self.server_state = ServerState()
203 
204         self.started = False
205         self.should_exit = False
206         self.force_exit = False
207 
208     def run(self):
209         process_id = os.getpid()
210 
211         config = self.config
212         if not config.loaded:
213             config.load()
214 
215         self.loop = config.loop_instance
216         self.logger = config.logger_instance
217         self.lifespan = config.lifespan_class(config)
218 
219         self.install_signal_handlers()
220 
221         self.logger.info("Started server process [{}]".format(process_id))
222         self.loop.run_until_complete(self.startup())
223         self.loop.run_until_complete(self.main_loop())
224         self.loop.run_until_complete(self.shutdown())
225         self.loop.stop()
226         self.logger.info("Finished server process [{}]".format(process_id))
227 
228     async def startup(self):
229         config = self.config
230 
231         await self.lifespan.startup()
232 
233         create_protocol = functools.partial(
234             config.http_protocol_class, config=config, server_state=self.server_state
235         )
236 
237         if config.sockets is not None:
238             # Explicitly passed a list of open sockets.
239             # We use this when the server is run from a Gunicorn worker.
240             self.servers = []
241             for socket in config.sockets:
242                 server = await self.loop.create_server(create_protocol, sock=socket)
243                 self.servers.append(server)
244 
245         elif config.fd is not None:
246             # Use an existing socket, from a file descriptor.
247             sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)
248             server = await self.loop.create_server(create_protocol, sock=sock)
249             message = "Uvicorn running on socket %s (Press CTRL+C to quit)"
250             self.logger.info(message % str(sock.getsockname()))
251             self.servers = [server]
252 
253         elif config.uds is not None:
254             # Create a socket using UNIX domain socket.
255             server = await self.loop.create_unix_server(
256                 create_protocol, path=config.uds
257             )
258             message = "Uvicorn running on unix socket %s (Press CTRL+C to quit)"
259             self.logger.info(message % config.uds)
260             self.servers = [server]
261 
262         else:
263             # Standard case. Create a socket from a host/port pair.
264             server = await self.loop.create_server(
265                 create_protocol, host=config.host, port=config.port
266             )
267             message = "Uvicorn running on http://%s:%d (Press CTRL+C to quit)"
268             self.logger.info(message % (config.host, config.port))
269             self.servers = [server]
270 
271         self.started = True
272 
273     async def main_loop(self):
274         counter = 0
275         should_exit = await self.on_tick(counter)
276         while not should_exit:
277             counter += 1
278             counter = counter % 864000
279             await asyncio.sleep(0.1)
280             should_exit = await self.on_tick(counter)
281 
282     async def on_tick(self, counter) -> bool:
283         # Update the default headers, once per second.
284         if counter % 10 == 0:
285             current_time = time.time()
286             current_date = formatdate(current_time, usegmt=True).encode()
287             self.server_state.default_headers = [
288                 (b"server", b"uvicorn"),
289                 (b"date", current_date),
290             ]
291 
292         # Callback to `callback_notify` once every `timeout_notify` seconds.
293         if self.config.callback_notify is not None:
294             if counter % (10 * self.config.timeout_notify) == 0:
295                 await self.config.callback_notify()
296 
297         # Determine if we should exit.
298         if self.should_exit:
299             return True
300         if self.config.limit_max_requests is not None:
301             return self.server_state.total_requests >= self.config.limit_max_requests
302         return False
303 
304     async def shutdown(self):
305         self.logger.info("Shutting down")
306 
307         # Stop accepting new connections.
308         if not self.config.sockets:
309             for server in self.servers:
310                 server.close()
311             for server in self.servers:
312                 await server.wait_closed()
313 
314         # Request shutdown on all existing connections.
315         for connection in list(self.server_state.connections):
316             connection.shutdown()
317         await asyncio.sleep(0.1)
318 
319         # Wait for existing connections to finish sending responses.
320         if self.server_state.connections and not self.force_exit:
321             msg = "Waiting for connections to close. (CTRL+C to force quit)"
322             self.logger.info(msg)
323             while self.server_state.connections and not self.force_exit:
324                 await asyncio.sleep(0.1)
325 
326         # Wait for existing tasks to complete.
327         if self.server_state.tasks and not self.force_exit:
328             msg = "Waiting for background tasks to complete. (CTRL+C to force quit)"
329             self.logger.info(msg)
330             while self.server_state.tasks and not self.force_exit:
331                 await asyncio.sleep(0.1)
332 
333         # Send the lifespan shutdown event, and wait for application shutdown.
334         if not self.force_exit:
335             await self.lifespan.shutdown()
336 
337     def install_signal_handlers(self):
338         try:
339             for sig in HANDLED_SIGNALS:
340                 self.loop.add_signal_handler(sig, self.handle_exit, sig, None)
341         except NotImplementedError as exc:
342             # Windows
343             for sig in HANDLED_SIGNALS:
344                 signal.signal(sig, self.handle_exit)
345 
346     def handle_exit(self, sig, frame):
347         if self.should_exit:
348             self.force_exit = True
349         else:
350             self.should_exit = True
351 
352 
353 if __name__ == "__main__":
354     main()
355
```

Path: `uvicorn/__init__.py`
Content:
```
1 from uvicorn.main import main, run
2 
3 __version__ = "0.4.1"
4 __all__ = ["main", "run"]
5
```
--- 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/uvicorn/__init__.py b/uvicorn/__init__.py
--- a/uvicorn/__init__.py
+++ b/uvicorn/__init__.py
@@ -1,4 +1,4 @@
 from uvicorn.main import main, run
 
-__version__ = "0.4.1"
+__version__ = "0.4.2"
 __all__ = ["main", "run"]
diff --git a/uvicorn/main.py b/uvicorn/main.py
--- a/uvicorn/main.py
+++ b/uvicorn/main.py
@@ -2,6 +2,7 @@
 import functools
 import os
 import signal
+import socket
 import sys
 import time
 from email.utils import formatdate

{"golden_diff": "diff --git a/uvicorn/__init__.py b/uvicorn/__init__.py\n--- a/uvicorn/__init__.py\n+++ b/uvicorn/__init__.py\n@@ -1,4 +1,4 @@\n from uvicorn.main import main, run\n \n-__version__ = \"0.4.1\"\n+__version__ = \"0.4.2\"\n __all__ = [\"main\", \"run\"]\ndiff --git a/uvicorn/main.py b/uvicorn/main.py\n--- a/uvicorn/main.py\n+++ b/uvicorn/main.py\n@@ -2,6 +2,7 @@\n import functools\n import os\n import signal\n+import socket\n import sys\n import time\n from email.utils import formatdate\n", "issue": "Deploying inside a process manager: must account for inherited socket family and type\nHi,\r\n\r\nI get an error when trying to run uvicorn with Circus, but only if using a socket with file descriptor (which I'd like to do to increase the number of processes).\r\n\r\ncircus.ini:\r\n```\r\n[socket:web]\r\nhost = 0.0.0.0\r\nport = 80\r\n[watcher:uvicorn]\r\ncmd = uvicorn\r\n# args = --host 0.0.0.0 --port 80 satemo.asgi:application \r\n# --> works ok\r\nargs = --fd $(circus.sockets.web) satemo.asgi:application \r\n# --> Fails\r\nuse_sockets = True\r\nnumprocesses = 1\r\n```\r\n\r\nError:\r\n```\r\nFile \"c:\\nss\\venv\\channels2\\lib\\site-packages\\uvicorn\\main.py\", line 247, in startup\r\n    sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)\r\nUnboundLocalError: local variable 'socket' referenced before assignment\r\n```\r\n\r\nEnvironment:\r\n* Windows 10\r\n* Python 3.6.5\r\n* uvicorn 0.4.1\r\n\n", "before_files": [{"content": "import asyncio\nimport functools\nimport os\nimport signal\nimport sys\nimport time\nfrom email.utils import formatdate\n\nimport click\n\nfrom uvicorn.config import (\n    HTTP_PROTOCOLS,\n    LIFESPAN,\n    LOG_LEVELS,\n    LOOP_SETUPS,\n    WS_PROTOCOLS,\n    Config,\n    get_logger,\n)\nfrom uvicorn.reloaders.statreload import StatReload\n\nLEVEL_CHOICES = click.Choice(LOG_LEVELS.keys())\nHTTP_CHOICES = click.Choice(HTTP_PROTOCOLS.keys())\nWS_CHOICES = click.Choice(WS_PROTOCOLS.keys())\nLIFESPAN_CHOICES = click.Choice(LIFESPAN.keys())\nLOOP_CHOICES = click.Choice(LOOP_SETUPS.keys())\n\nHANDLED_SIGNALS = (\n    signal.SIGINT,  # Unix signal 2. Sent by Ctrl+C.\n    signal.SIGTERM,  # Unix signal 15. Sent by `kill <pid>`.\n)\n\n\n@click.command()\n@click.argument(\"app\")\n@click.option(\n    \"--host\",\n    type=str,\n    default=\"127.0.0.1\",\n    help=\"Bind socket to this host.\",\n    show_default=True,\n)\n@click.option(\n    \"--port\",\n    type=int,\n    default=8000,\n    help=\"Bind socket to this port.\",\n    show_default=True,\n)\n@click.option(\"--uds\", type=str, default=None, help=\"Bind to a UNIX domain socket.\")\n@click.option(\n    \"--fd\", type=int, default=None, help=\"Bind to socket from this file descriptor.\"\n)\n@click.option(\n    \"--loop\",\n    type=LOOP_CHOICES,\n    default=\"auto\",\n    help=\"Event loop implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--http\",\n    type=HTTP_CHOICES,\n    default=\"auto\",\n    help=\"HTTP protocol implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--ws\",\n    type=WS_CHOICES,\n    default=\"auto\",\n    help=\"WebSocket protocol implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--lifespan\",\n    type=LIFESPAN_CHOICES,\n    default=\"auto\",\n    help=\"Lifespan implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--wsgi\",\n    is_flag=True,\n    default=False,\n    help=\"Use WSGI as the application interface, instead of ASGI.\",\n)\n@click.option(\"--debug\", is_flag=True, default=False, help=\"Enable debug mode.\")\n@click.option(\n    \"--log-level\",\n    type=LEVEL_CHOICES,\n    default=\"info\",\n    help=\"Log level.\",\n    show_default=True,\n)\n@click.option(\n    \"--no-access-log\", is_flag=True, default=False, help=\"Disable access log.\"\n)\n@click.option(\n    \"--proxy-headers\",\n    is_flag=True,\n    default=False,\n    help=\"Use X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info.\",\n)\n@click.option(\n    \"--root-path\",\n    type=str,\n    default=\"\",\n    help=\"Set the ASGI 'root_path' for applications submounted below a given URL path.\",\n)\n@click.option(\n    \"--limit-concurrency\",\n    type=int,\n    default=None,\n    help=\"Maximum number of concurrent connections or tasks to allow, before issuing HTTP 503 responses.\",\n)\n@click.option(\n    \"--limit-max-requests\",\n    type=int,\n    default=None,\n    help=\"Maximum number of requests to service before terminating the process.\",\n)\n@click.option(\n    \"--timeout-keep-alive\",\n    type=int,\n    default=5,\n    help=\"Close Keep-Alive connections if no new data is received within this timeout.\",\n    show_default=True,\n)\ndef main(\n    app,\n    host: str,\n    port: int,\n    uds: str,\n    fd: int,\n    loop: str,\n    http: str,\n    ws: str,\n    lifespan: str,\n    wsgi: bool,\n    debug: bool,\n    log_level: str,\n    no_access_log: bool,\n    proxy_headers: bool,\n    root_path: str,\n    limit_concurrency: int,\n    limit_max_requests: int,\n    timeout_keep_alive: int,\n):\n    sys.path.insert(0, \".\")\n\n    kwargs = {\n        \"app\": app,\n        \"host\": host,\n        \"port\": port,\n        \"uds\": uds,\n        \"fd\": fd,\n        \"loop\": loop,\n        \"http\": http,\n        \"ws\": ws,\n        \"lifespan\": lifespan,\n        \"log_level\": log_level,\n        \"access_log\": not no_access_log,\n        \"wsgi\": wsgi,\n        \"debug\": debug,\n        \"proxy_headers\": proxy_headers,\n        \"root_path\": root_path,\n        \"limit_concurrency\": limit_concurrency,\n        \"limit_max_requests\": limit_max_requests,\n        \"timeout_keep_alive\": timeout_keep_alive,\n    }\n\n    if debug:\n        logger = get_logger(log_level)\n        reloader = StatReload(logger)\n        reloader.run(run, kwargs)\n    else:\n        run(**kwargs)\n\n\ndef run(app, **kwargs):\n    config = Config(app, **kwargs)\n    server = Server(config=config)\n    server.run()\n\n\nclass ServerState:\n    \"\"\"\n    Shared servers state that is available between all protocol instances.\n    \"\"\"\n\n    def __init__(self):\n        self.total_requests = 0\n        self.connections = set()\n        self.tasks = set()\n        self.default_headers = []\n\n\nclass Server:\n    def __init__(self, config):\n        self.config = config\n        self.server_state = ServerState()\n\n        self.started = False\n        self.should_exit = False\n        self.force_exit = False\n\n    def run(self):\n        process_id = os.getpid()\n\n        config = self.config\n        if not config.loaded:\n            config.load()\n\n        self.loop = config.loop_instance\n        self.logger = config.logger_instance\n        self.lifespan = config.lifespan_class(config)\n\n        self.install_signal_handlers()\n\n        self.logger.info(\"Started server process [{}]\".format(process_id))\n        self.loop.run_until_complete(self.startup())\n        self.loop.run_until_complete(self.main_loop())\n        self.loop.run_until_complete(self.shutdown())\n        self.loop.stop()\n        self.logger.info(\"Finished server process [{}]\".format(process_id))\n\n    async def startup(self):\n        config = self.config\n\n        await self.lifespan.startup()\n\n        create_protocol = functools.partial(\n            config.http_protocol_class, config=config, server_state=self.server_state\n        )\n\n        if config.sockets is not None:\n            # Explicitly passed a list of open sockets.\n            # We use this when the server is run from a Gunicorn worker.\n            self.servers = []\n            for socket in config.sockets:\n                server = await self.loop.create_server(create_protocol, sock=socket)\n                self.servers.append(server)\n\n        elif config.fd is not None:\n            # Use an existing socket, from a file descriptor.\n            sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)\n            server = await self.loop.create_server(create_protocol, sock=sock)\n            message = \"Uvicorn running on socket %s (Press CTRL+C to quit)\"\n            self.logger.info(message % str(sock.getsockname()))\n            self.servers = [server]\n\n        elif config.uds is not None:\n            # Create a socket using UNIX domain socket.\n            server = await self.loop.create_unix_server(\n                create_protocol, path=config.uds\n            )\n            message = \"Uvicorn running on unix socket %s (Press CTRL+C to quit)\"\n            self.logger.info(message % config.uds)\n            self.servers = [server]\n\n        else:\n            # Standard case. Create a socket from a host/port pair.\n            server = await self.loop.create_server(\n                create_protocol, host=config.host, port=config.port\n            )\n            message = \"Uvicorn running on http://%s:%d (Press CTRL+C to quit)\"\n            self.logger.info(message % (config.host, config.port))\n            self.servers = [server]\n\n        self.started = True\n\n    async def main_loop(self):\n        counter = 0\n        should_exit = await self.on_tick(counter)\n        while not should_exit:\n            counter += 1\n            counter = counter % 864000\n            await asyncio.sleep(0.1)\n            should_exit = await self.on_tick(counter)\n\n    async def on_tick(self, counter) -> bool:\n        # Update the default headers, once per second.\n        if counter % 10 == 0:\n            current_time = time.time()\n            current_date = formatdate(current_time, usegmt=True).encode()\n            self.server_state.default_headers = [\n                (b\"server\", b\"uvicorn\"),\n                (b\"date\", current_date),\n            ]\n\n        # Callback to `callback_notify` once every `timeout_notify` seconds.\n        if self.config.callback_notify is not None:\n            if counter % (10 * self.config.timeout_notify) == 0:\n                await self.config.callback_notify()\n\n        # Determine if we should exit.\n        if self.should_exit:\n            return True\n        if self.config.limit_max_requests is not None:\n            return self.server_state.total_requests >= self.config.limit_max_requests\n        return False\n\n    async def shutdown(self):\n        self.logger.info(\"Shutting down\")\n\n        # Stop accepting new connections.\n        if not self.config.sockets:\n            for server in self.servers:\n                server.close()\n            for server in self.servers:\n                await server.wait_closed()\n\n        # Request shutdown on all existing connections.\n        for connection in list(self.server_state.connections):\n            connection.shutdown()\n        await asyncio.sleep(0.1)\n\n        # Wait for existing connections to finish sending responses.\n        if self.server_state.connections and not self.force_exit:\n            msg = \"Waiting for connections to close. (CTRL+C to force quit)\"\n            self.logger.info(msg)\n            while self.server_state.connections and not self.force_exit:\n                await asyncio.sleep(0.1)\n\n        # Wait for existing tasks to complete.\n        if self.server_state.tasks and not self.force_exit:\n            msg = \"Waiting for background tasks to complete. (CTRL+C to force quit)\"\n            self.logger.info(msg)\n            while self.server_state.tasks and not self.force_exit:\n                await asyncio.sleep(0.1)\n\n        # Send the lifespan shutdown event, and wait for application shutdown.\n        if not self.force_exit:\n            await self.lifespan.shutdown()\n\n    def install_signal_handlers(self):\n        try:\n            for sig in HANDLED_SIGNALS:\n                self.loop.add_signal_handler(sig, self.handle_exit, sig, None)\n        except NotImplementedError as exc:\n            # Windows\n            for sig in HANDLED_SIGNALS:\n                signal.signal(sig, self.handle_exit)\n\n    def handle_exit(self, sig, frame):\n        if self.should_exit:\n            self.force_exit = True\n        else:\n            self.should_exit = True\n\n\nif __name__ == \"__main__\":\n    main()\n", "path": "uvicorn/main.py"}, {"content": "from uvicorn.main import main, run\n\n__version__ = \"0.4.1\"\n__all__ = [\"main\", \"run\"]\n", "path": "uvicorn/__init__.py"}], "after_files": [{"content": "import asyncio\nimport functools\nimport os\nimport signal\nimport socket\nimport sys\nimport time\nfrom email.utils import formatdate\n\nimport click\n\nfrom uvicorn.config import (\n    HTTP_PROTOCOLS,\n    LIFESPAN,\n    LOG_LEVELS,\n    LOOP_SETUPS,\n    WS_PROTOCOLS,\n    Config,\n    get_logger,\n)\nfrom uvicorn.reloaders.statreload import StatReload\n\nLEVEL_CHOICES = click.Choice(LOG_LEVELS.keys())\nHTTP_CHOICES = click.Choice(HTTP_PROTOCOLS.keys())\nWS_CHOICES = click.Choice(WS_PROTOCOLS.keys())\nLIFESPAN_CHOICES = click.Choice(LIFESPAN.keys())\nLOOP_CHOICES = click.Choice(LOOP_SETUPS.keys())\n\nHANDLED_SIGNALS = (\n    signal.SIGINT,  # Unix signal 2. Sent by Ctrl+C.\n    signal.SIGTERM,  # Unix signal 15. Sent by `kill <pid>`.\n)\n\n\n@click.command()\n@click.argument(\"app\")\n@click.option(\n    \"--host\",\n    type=str,\n    default=\"127.0.0.1\",\n    help=\"Bind socket to this host.\",\n    show_default=True,\n)\n@click.option(\n    \"--port\",\n    type=int,\n    default=8000,\n    help=\"Bind socket to this port.\",\n    show_default=True,\n)\n@click.option(\"--uds\", type=str, default=None, help=\"Bind to a UNIX domain socket.\")\n@click.option(\n    \"--fd\", type=int, default=None, help=\"Bind to socket from this file descriptor.\"\n)\n@click.option(\n    \"--loop\",\n    type=LOOP_CHOICES,\n    default=\"auto\",\n    help=\"Event loop implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--http\",\n    type=HTTP_CHOICES,\n    default=\"auto\",\n    help=\"HTTP protocol implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--ws\",\n    type=WS_CHOICES,\n    default=\"auto\",\n    help=\"WebSocket protocol implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--lifespan\",\n    type=LIFESPAN_CHOICES,\n    default=\"auto\",\n    help=\"Lifespan implementation.\",\n    show_default=True,\n)\n@click.option(\n    \"--wsgi\",\n    is_flag=True,\n    default=False,\n    help=\"Use WSGI as the application interface, instead of ASGI.\",\n)\n@click.option(\"--debug\", is_flag=True, default=False, help=\"Enable debug mode.\")\n@click.option(\n    \"--log-level\",\n    type=LEVEL_CHOICES,\n    default=\"info\",\n    help=\"Log level.\",\n    show_default=True,\n)\n@click.option(\n    \"--no-access-log\", is_flag=True, default=False, help=\"Disable access log.\"\n)\n@click.option(\n    \"--proxy-headers\",\n    is_flag=True,\n    default=False,\n    help=\"Use X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info.\",\n)\n@click.option(\n    \"--root-path\",\n    type=str,\n    default=\"\",\n    help=\"Set the ASGI 'root_path' for applications submounted below a given URL path.\",\n)\n@click.option(\n    \"--limit-concurrency\",\n    type=int,\n    default=None,\n    help=\"Maximum number of concurrent connections or tasks to allow, before issuing HTTP 503 responses.\",\n)\n@click.option(\n    \"--limit-max-requests\",\n    type=int,\n    default=None,\n    help=\"Maximum number of requests to service before terminating the process.\",\n)\n@click.option(\n    \"--timeout-keep-alive\",\n    type=int,\n    default=5,\n    help=\"Close Keep-Alive connections if no new data is received within this timeout.\",\n    show_default=True,\n)\ndef main(\n    app,\n    host: str,\n    port: int,\n    uds: str,\n    fd: int,\n    loop: str,\n    http: str,\n    ws: str,\n    lifespan: str,\n    wsgi: bool,\n    debug: bool,\n    log_level: str,\n    no_access_log: bool,\n    proxy_headers: bool,\n    root_path: str,\n    limit_concurrency: int,\n    limit_max_requests: int,\n    timeout_keep_alive: int,\n):\n    sys.path.insert(0, \".\")\n\n    kwargs = {\n        \"app\": app,\n        \"host\": host,\n        \"port\": port,\n        \"uds\": uds,\n        \"fd\": fd,\n        \"loop\": loop,\n        \"http\": http,\n        \"ws\": ws,\n        \"lifespan\": lifespan,\n        \"log_level\": log_level,\n        \"access_log\": not no_access_log,\n        \"wsgi\": wsgi,\n        \"debug\": debug,\n        \"proxy_headers\": proxy_headers,\n        \"root_path\": root_path,\n        \"limit_concurrency\": limit_concurrency,\n        \"limit_max_requests\": limit_max_requests,\n        \"timeout_keep_alive\": timeout_keep_alive,\n    }\n\n    if debug:\n        logger = get_logger(log_level)\n        reloader = StatReload(logger)\n        reloader.run(run, kwargs)\n    else:\n        run(**kwargs)\n\n\ndef run(app, **kwargs):\n    config = Config(app, **kwargs)\n    server = Server(config=config)\n    server.run()\n\n\nclass ServerState:\n    \"\"\"\n    Shared servers state that is available between all protocol instances.\n    \"\"\"\n\n    def __init__(self):\n        self.total_requests = 0\n        self.connections = set()\n        self.tasks = set()\n        self.default_headers = []\n\n\nclass Server:\n    def __init__(self, config):\n        self.config = config\n        self.server_state = ServerState()\n\n        self.started = False\n        self.should_exit = False\n        self.force_exit = False\n\n    def run(self):\n        process_id = os.getpid()\n\n        config = self.config\n        if not config.loaded:\n            config.load()\n\n        self.loop = config.loop_instance\n        self.logger = config.logger_instance\n        self.lifespan = config.lifespan_class(config)\n\n        self.install_signal_handlers()\n\n        self.logger.info(\"Started server process [{}]\".format(process_id))\n        self.loop.run_until_complete(self.startup())\n        self.loop.run_until_complete(self.main_loop())\n        self.loop.run_until_complete(self.shutdown())\n        self.loop.stop()\n        self.logger.info(\"Finished server process [{}]\".format(process_id))\n\n    async def startup(self):\n        config = self.config\n\n        await self.lifespan.startup()\n\n        create_protocol = functools.partial(\n            config.http_protocol_class, config=config, server_state=self.server_state\n        )\n\n        if config.sockets is not None:\n            # Explicitly passed a list of open sockets.\n            # We use this when the server is run from a Gunicorn worker.\n            self.servers = []\n            for socket in config.sockets:\n                server = await self.loop.create_server(create_protocol, sock=socket)\n                self.servers.append(server)\n\n        elif config.fd is not None:\n            # Use an existing socket, from a file descriptor.\n            sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)\n            server = await self.loop.create_server(create_protocol, sock=sock)\n            message = \"Uvicorn running on socket %s (Press CTRL+C to quit)\"\n            self.logger.info(message % str(sock.getsockname()))\n            self.servers = [server]\n\n        elif config.uds is not None:\n            # Create a socket using UNIX domain socket.\n            server = await self.loop.create_unix_server(\n                create_protocol, path=config.uds\n            )\n            message = \"Uvicorn running on unix socket %s (Press CTRL+C to quit)\"\n            self.logger.info(message % config.uds)\n            self.servers = [server]\n\n        else:\n            # Standard case. Create a socket from a host/port pair.\n            server = await self.loop.create_server(\n                create_protocol, host=config.host, port=config.port\n            )\n            message = \"Uvicorn running on http://%s:%d (Press CTRL+C to quit)\"\n            self.logger.info(message % (config.host, config.port))\n            self.servers = [server]\n\n        self.started = True\n\n    async def main_loop(self):\n        counter = 0\n        should_exit = await self.on_tick(counter)\n        while not should_exit:\n            counter += 1\n            counter = counter % 864000\n            await asyncio.sleep(0.1)\n            should_exit = await self.on_tick(counter)\n\n    async def on_tick(self, counter) -> bool:\n        # Update the default headers, once per second.\n        if counter % 10 == 0:\n            current_time = time.time()\n            current_date = formatdate(current_time, usegmt=True).encode()\n            self.server_state.default_headers = [\n                (b\"server\", b\"uvicorn\"),\n                (b\"date\", current_date),\n            ]\n\n        # Callback to `callback_notify` once every `timeout_notify` seconds.\n        if self.config.callback_notify is not None:\n            if counter % (10 * self.config.timeout_notify) == 0:\n                await self.config.callback_notify()\n\n        # Determine if we should exit.\n        if self.should_exit:\n            return True\n        if self.config.limit_max_requests is not None:\n            return self.server_state.total_requests >= self.config.limit_max_requests\n        return False\n\n    async def shutdown(self):\n        self.logger.info(\"Shutting down\")\n\n        # Stop accepting new connections.\n        if not self.config.sockets:\n            for server in self.servers:\n                server.close()\n            for server in self.servers:\n                await server.wait_closed()\n\n        # Request shutdown on all existing connections.\n        for connection in list(self.server_state.connections):\n            connection.shutdown()\n        await asyncio.sleep(0.1)\n\n        # Wait for existing connections to finish sending responses.\n        if self.server_state.connections and not self.force_exit:\n            msg = \"Waiting for connections to close. (CTRL+C to force quit)\"\n            self.logger.info(msg)\n            while self.server_state.connections and not self.force_exit:\n                await asyncio.sleep(0.1)\n\n        # Wait for existing tasks to complete.\n        if self.server_state.tasks and not self.force_exit:\n            msg = \"Waiting for background tasks to complete. (CTRL+C to force quit)\"\n            self.logger.info(msg)\n            while self.server_state.tasks and not self.force_exit:\n                await asyncio.sleep(0.1)\n\n        # Send the lifespan shutdown event, and wait for application shutdown.\n        if not self.force_exit:\n            await self.lifespan.shutdown()\n\n    def install_signal_handlers(self):\n        try:\n            for sig in HANDLED_SIGNALS:\n                self.loop.add_signal_handler(sig, self.handle_exit, sig, None)\n        except NotImplementedError as exc:\n            # Windows\n            for sig in HANDLED_SIGNALS:\n                signal.signal(sig, self.handle_exit)\n\n    def handle_exit(self, sig, frame):\n        if self.should_exit:\n            self.force_exit = True\n        else:\n            self.should_exit = True\n\n\nif __name__ == \"__main__\":\n    main()\n", "path": "uvicorn/main.py"}, {"content": "from uvicorn.main import main, run\n\n__version__ = \"0.4.2\"\n__all__ = [\"main\", \"run\"]\n", "path": "uvicorn/__init__.py"}]}