From c1f1d177bbdc9ca17863a472a4a3ca7048d1eeb9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 18 Jul 2018 22:32:57 +0100 Subject: [PATCH] Improve PyPy and Windows support (#130) * Improve PyPy and Windows support * Use platform-appropriate defaults in uvicorn.run * Explicit encoding when using 'open' in setup.py * Version 0.2.13 * Fix to setup.py --- setup.py | 36 +++++++++++++++++++++++++++--------- uvicorn/__init__.py | 2 +- uvicorn/main.py | 26 +++++++++++++++++++++----- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/setup.py b/setup.py index 46738e7ed..79096eaf8 100755 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ import os import re import sys +import platform from setuptools import setup @@ -12,7 +13,8 @@ def get_version(package): """ Return package version as listed in `__version__` in `init.py`. """ - init_py = open(os.path.join(package, '__init__.py')).read() + path = os.path.join(package, '__init__.py') + init_py = open(path, 'r', encoding='utf8').read() return re.search("__version__ = ['\"]([^'\"]+)['\"]", init_py).group(1) @@ -20,7 +22,7 @@ def get_long_description(): """ Return the README. """ - return open('README.md', 'r').read() + return open('README.md', 'r', encoding='utf8').read() def get_packages(package): @@ -32,6 +34,28 @@ def get_packages(package): if os.path.exists(os.path.join(dirpath, '__init__.py'))] +if platform.python_implementation() == 'PyPy': + requirements = [ + 'click', + 'h11', + 'websockets>=6.0' + ] +elif platform.system() == 'Windows' or platform.system().startswith('CYGWIN'): + requirements = [ + 'click', + 'h11', + 'websockets>=6.0' + ] +else: + requirements = [ + 'click', + 'h11', + 'httptools', + 'uvloop', + 'websockets>=6.0' + ] + + setup( name='uvicorn', version=get_version('uvicorn'), @@ -43,13 +67,7 @@ def get_packages(package): author='Tom Christie', author_email='tom@tomchristie.com', packages=get_packages('uvicorn'), - install_requires=[ - 'click', - 'h11', - 'httptools', - 'uvloop', - 'websockets>=6.0' - ], + install_requires=requirements, classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Web Environment', diff --git a/uvicorn/__init__.py b/uvicorn/__init__.py index 31dbed8f5..b09994e86 100644 --- a/uvicorn/__init__.py +++ b/uvicorn/__init__.py @@ -1,4 +1,4 @@ from uvicorn.main import main, run -__version__ = "0.2.12" +__version__ = "0.2.13" __all__ = ["main", "run"] diff --git a/uvicorn/main.py b/uvicorn/main.py index 820b69e73..6b31bce6a 100644 --- a/uvicorn/main.py +++ b/uvicorn/main.py @@ -6,6 +6,7 @@ import signal import os import logging +import platform import sys @@ -22,12 +23,23 @@ HTTP_PROTOCOLS = {"h11": H11Protocol, "httptools": HttpToolsProtocol} +if platform.python_implementation() == 'PyPy': + DEFAULT_LOOP = 'asyncio' + DEFAULT_PARSER = 'h11' +elif platform.system() == 'Windows' or platform.system().startswith('CYGWIN'): + DEFAULT_LOOP = 'asyncio' + DEFAULT_PARSER = 'h11' +else: + DEFAULT_LOOP = 'uvloop' + DEFAULT_PARSER = 'httptools' + + @click.command() @click.argument("app") @click.option("--host", type=str, default="127.0.0.1", help="Host") @click.option("--port", type=int, default=8000, help="Port") -@click.option("--loop", type=LOOP_CHOICES, default="uvloop", help="Event loop") -@click.option("--http", type=HTTP_CHOICES, default="httptools", help="HTTP Handler") +@click.option("--loop", type=LOOP_CHOICES, default=DEFAULT_LOOP, help="Event loop") +@click.option("--http", type=HTTP_CHOICES, default=DEFAULT_PARSER, help="HTTP Handler") @click.option("--workers", type=int, default=1, help="Number of worker processes") @click.option("--log-level", type=LEVEL_CHOICES, default="info", help="Log level") def main(app, host: str, port: int, loop: str, http: str, workers: int, log_level: str): @@ -54,9 +66,9 @@ def run(app, host="127.0.0.1", port=8000, log_level="info"): log_level = LOG_LEVELS[log_level] logging.basicConfig(format="%(levelname)s: %(message)s", level=log_level) - loop = get_event_loop("uvloop") + loop = get_event_loop(DEFAULT_LOOP) logger = logging.getLogger() - protocol_class = HttpToolsProtocol + protocol_class = {'httptools': HttpToolsProtocol, 'h11': H11Protocol}[DEFAULT_PARSER] server = Server(app, host, port, loop, logger, protocol_class) server.run() @@ -142,7 +154,11 @@ def run(self): self.loop.run_forever() def handle_exit(self, sig, frame): - self.logger.warning("Received signal {}. Shutting down.".format(sig.name)) + if hasattr(sig, 'name'): + msg = "Received signal %s. Shutting down." % sig.name + else: + msg = "Received signal. Shutting down." + self.logger.warning(msg) self.should_exit = True def create_protocol(self):