From ec7e4390e8916dda8590d0a07edc594dadc31ebd Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Wed, 10 Mar 2021 11:19:38 +0200 Subject: [PATCH] Fix some examples and docs (#2052) --- examples/Dockerfile | 13 ++---- examples/log_request_id.py | 91 ++++++++++++++++-------------------- examples/override_logging.py | 19 ++++---- examples/pytest_xdist.py | 20 ++++---- examples/vhosts.py | 32 +++++++------ sanic/app.py | 22 +++++++++ 6 files changed, 107 insertions(+), 90 deletions(-) diff --git a/examples/Dockerfile b/examples/Dockerfile index edd76218..aeaeb516 100644 --- a/examples/Dockerfile +++ b/examples/Dockerfile @@ -1,11 +1,8 @@ -FROM python:3.5 -MAINTAINER Channel Cat +FROM sanicframework/sanic:LTS -ADD . /code -RUN pip3 install git+https://github.com/channelcat/sanic +RUN mkdir /srv +COPY . /srv -EXPOSE 8000 +WORKDIR /srv -WORKDIR /code - -CMD ["python", "simple_server.py"] \ No newline at end of file +CMD ["sanic", "simple_server.app"] diff --git a/examples/log_request_id.py b/examples/log_request_id.py index 687d79da..27d987bc 100644 --- a/examples/log_request_id.py +++ b/examples/log_request_id.py @@ -1,86 +1,75 @@ -''' -Based on example from https://github.com/Skyscanner/aiotask-context -and `examples/{override_logging,run_async}.py`. - -Needs https://github.com/Skyscanner/aiotask-context/tree/52efbc21e2e1def2d52abb9a8e951f3ce5e6f690 or newer - -$ pip install git+https://github.com/Skyscanner/aiotask-context.git -''' - -import asyncio -import uuid import logging -from signal import signal, SIGINT -from sanic import Sanic -from sanic import response - -import uvloop import aiotask_context as context +from sanic import Sanic, response + + log = logging.getLogger(__name__) class RequestIdFilter(logging.Filter): def filter(self, record): - record.request_id = context.get('X-Request-ID') + try: + record.request_id = context.get("X-Request-ID") + except ValueError: + record.request_id = "n/a" return True LOG_SETTINGS = { - 'version': 1, - 'disable_existing_loggers': False, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - 'level': 'DEBUG', - 'formatter': 'default', - 'filters': ['requestid'], + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "level": "DEBUG", + "formatter": "default", + "filters": ["requestid"], }, }, - 'filters': { - 'requestid': { - '()': RequestIdFilter, + "filters": { + "requestid": { + "()": RequestIdFilter, }, }, - 'formatters': { - 'default': { - 'format': '%(asctime)s %(levelname)s %(name)s:%(lineno)d %(request_id)s | %(message)s', + "formatters": { + "default": { + "format": "%(asctime)s %(levelname)s %(name)s:%(lineno)d %(request_id)s | %(message)s", }, }, - 'loggers': { - '': { - 'level': 'DEBUG', - 'handlers': ['console'], - 'propagate': True - }, - } + "loggers": { + "": {"level": "DEBUG", "handlers": ["console"], "propagate": True}, + }, } app = Sanic(__name__, log_config=LOG_SETTINGS) -@app.middleware('request') +@app.on_request async def set_request_id(request): - request_id = request.headers.get('X-Request-ID') or str(uuid.uuid4()) + request_id = request.id context.set("X-Request-ID", request_id) + log.info(f"Setting {request.id=}") + + +@app.on_response +async def set_request_header(request, response): + response.headers["X-Request-ID"] = request.id @app.route("/") async def test(request): - log.debug('X-Request-ID: %s', context.get('X-Request-ID')) - log.info('Hello from test!') + log.debug("X-Request-ID: %s", context.get("X-Request-ID")) + log.info("Hello from test!") return response.json({"test": True}) -if __name__ == '__main__': - asyncio.set_event_loop(uvloop.new_event_loop()) - server = app.create_server(host="0.0.0.0", port=8000, return_asyncio_server=True) - loop = asyncio.get_event_loop() +@app.before_server_start +def setup(app, loop): loop.set_task_factory(context.task_factory) - task = asyncio.ensure_future(server) - try: - loop.run_forever() - except: - loop.stop() + + +if __name__ == "__main__": + app.run(port=9999, debug=True) diff --git a/examples/override_logging.py b/examples/override_logging.py index 99d26997..c60098e7 100644 --- a/examples/override_logging.py +++ b/examples/override_logging.py @@ -1,24 +1,23 @@ -from sanic import Sanic -from sanic import response import logging +from sanic import Sanic, text + + logging_format = "[%(asctime)s] %(process)d-%(levelname)s " logging_format += "%(module)s::%(funcName)s():l%(lineno)d: " logging_format += "%(message)s" -logging.basicConfig( - format=logging_format, - level=logging.DEBUG -) +logging.basicConfig(format=logging_format, level=logging.DEBUG) log = logging.getLogger() # Set logger to override default basicConfig -sanic = Sanic() +app = Sanic("app") -@sanic.route("/") +@app.route("/") def test(request): log.info("received request; responding with 'hey'") - return response.text("hey") + return text("hey") -sanic.run(host="0.0.0.0", port=8000) + +app.run(host="0.0.0.0", port=8000) diff --git a/examples/pytest_xdist.py b/examples/pytest_xdist.py index 06730016..7c201903 100644 --- a/examples/pytest_xdist.py +++ b/examples/pytest_xdist.py @@ -9,15 +9,19 @@ Run with xdist params: $ pytest examples/pytest_xdist.py -n 8 # 8 workers """ import re + +import pytest + +from sanic_testing import SanicTestClient +from sanic_testing.testing import PORT as PORT_BASE + from sanic import Sanic from sanic.response import text -from sanic.testing import PORT as PORT_BASE, SanicTestClient -import pytest @pytest.fixture(scope="session") def test_port(worker_id): - m = re.search(r'[0-9]+', worker_id) + m = re.search(r"[0-9]+", worker_id) if m: num_id = m.group(0) else: @@ -30,9 +34,9 @@ def test_port(worker_id): def app(): app = Sanic() - @app.route('/') + @app.route("/") async def index(request): - return text('OK') + return text("OK") return app @@ -42,8 +46,8 @@ def client(app, test_port): return SanicTestClient(app, test_port) -@pytest.mark.parametrize('run_id', range(100)) +@pytest.mark.parametrize("run_id", range(100)) def test_index(client, run_id): - request, response = client._sanic_endpoint_test('get', '/') + request, response = client._sanic_endpoint_test("get", "/") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" diff --git a/examples/vhosts.py b/examples/vhosts.py index a6f946bc..57d42e9d 100644 --- a/examples/vhosts.py +++ b/examples/vhosts.py @@ -1,39 +1,45 @@ -from sanic import response -from sanic import Sanic +from sanic import Sanic, response from sanic.blueprints import Blueprint + # Usage # curl -H "Host: example.com" localhost:8000 # curl -H "Host: sub.example.com" localhost:8000 # curl -H "Host: bp.example.com" localhost:8000/question # curl -H "Host: bp.example.com" localhost:8000/answer -app = Sanic() +app = Sanic(__name__) bp = Blueprint("bp", host="bp.example.com") -@app.route('/', host=["example.com", - "somethingelse.com", - "therestofyourdomains.com"]) -async def hello(request): +@app.route( + "/", host=["example.com", "somethingelse.com", "therestofyourdomains.com"] +) +async def hello_0(request): return response.text("Some defaults") -@app.route('/', host="sub.example.com") -async def hello(request): +@app.route("/", host="sub.example.com") +async def hello_1(request): return response.text("42") @bp.route("/question") -async def hello(request): +async def hello_2(request): return response.text("What is the meaning of life?") @bp.route("/answer") -async def hello(request): +async def hello_3(request): return response.text("42") + +@app.get("/name") +def name(request): + return response.text(request.app.url_for("name", _external=True)) + + app.blueprint(bp) -if __name__ == '__main__': - app.run(host="0.0.0.0", port=8000) \ No newline at end of file +if __name__ == "__main__": + app.run(host="0.0.0.0", port=8000) diff --git a/sanic/app.py b/sanic/app.py index 23cc68ea..612c811f 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -358,6 +358,28 @@ class Sanic(BaseSanic): Keyword arguments that are not request parameters will be included in the output URL's query string. + There are several _special_ keyword arguments that will alter how the + URL will be returned: + + 1. **_anchor**: ``str`` - Adds an ``#anchor`` to the end + 2. **_scheme**: ``str`` - Should be either ``"http"`` or ``"https"``, + default is ``"http"`` + 3. **_external**: ``bool`` - Whether to return the path or a full URL + with scheme and host + 4. **_host**: ``str`` - Used when one or more hosts are defined for a + route to tell Sanic which to use + (only applies with ``_external=True``) + 5. **_server**: ``str`` - If not using ``_host``, this will be used + for defining the hostname of the URL + (only applies with ``_external=True``), + defaults to ``app.config.SERVER_NAME`` + + If you want the PORT to appear in your URL, you should set it in: + + .. code-block:: + + app.config.SERVER_NAME = "myserver:7777" + `See user guide `__