Merge pull request #9 from channelcat/master

merging upstream master branch
This commit is contained in:
7 2017-08-02 09:04:31 -07:00 committed by GitHub
commit 181ffb00a7
6 changed files with 64 additions and 40 deletions

View File

@ -1,4 +1,5 @@
sudo: false sudo: false
dist: precise
language: python language: python
cache: cache:
directories: directories:

View File

@ -55,6 +55,16 @@ Documentation
:target: https://pypi.python.org/pypi/sanic/ :target: https://pypi.python.org/pypi/sanic/
.. |PyPI version| image:: https://img.shields.io/pypi/pyversions/sanic.svg .. |PyPI version| image:: https://img.shields.io/pypi/pyversions/sanic.svg
:target: https://pypi.python.org/pypi/sanic/ :target: https://pypi.python.org/pypi/sanic/
Examples
--------
`Non-Core examples <https://github.com/channelcat/sanic/wiki/Examples/>`_. Examples of plugins and Sanic that are outside the scope of Sanic core.
`Extensions <https://github.com/channelcat/sanic/wiki/Extensions/>`_. Sanic extensions created by the community.
`Projects <https://github.com/channelcat/sanic/wiki/Projects/>`_. Sanic in production use.
TODO TODO
---- ----

View File

@ -33,9 +33,7 @@ class Sanic:
logging.config.dictConfig(log_config) logging.config.dictConfig(log_config)
# Only set up a default log handler if the # Only set up a default log handler if the
# end-user application didn't set anything up. # end-user application didn't set anything up.
if not (logging.root.handlers and if not logging.root.handlers and log.level == logging.NOTSET:
log.level == logging.NOTSET and
log_config):
formatter = logging.Formatter( formatter = logging.Formatter(
"%(asctime)s: %(levelname)s: %(message)s") "%(asctime)s: %(levelname)s: %(message)s")
handler = logging.StreamHandler() handler = logging.StreamHandler()

View File

@ -208,44 +208,39 @@ class Unauthorized(SanicException):
""" """
Unauthorized exception (401 HTTP status code). Unauthorized exception (401 HTTP status code).
:param message: Message describing the exception.
:param scheme: Name of the authentication scheme to be used. :param scheme: Name of the authentication scheme to be used.
:param challenge: A dict containing values to add to the WWW-Authenticate
header that is generated. This is especially useful when dealing with When present, kwargs is used to complete the WWW-Authentication header.
the Digest scheme. (optional)
Examples:: Examples::
# With a Basic auth-scheme, realm MUST be present: # With a Basic auth-scheme, realm MUST be present:
challenge = {"realm": "Restricted Area"} raise Unauthorized("Auth required.", "Basic", realm="Restricted Area")
raise Unauthorized("Auth required.", "Basic", challenge)
# With a Digest auth-scheme, things are a bit more complicated: # With a Digest auth-scheme, things are a bit more complicated:
challenge = { raise Unauthorized("Auth required.",
"realm": "Restricted Area", "Digest",
"qop": "auth, auth-int", realm="Restricted Area",
"algorithm": "MD5", qop="auth, auth-int",
"nonce": "abcdef", algorithm="MD5",
"opaque": "zyxwvu" nonce="abcdef",
} opaque="zyxwvu")
raise Unauthorized("Auth required.", "Digest", challenge)
# With a Bearer auth-scheme, realm is optional: # With a Bearer auth-scheme, realm is optional so you can write:
challenge = {"realm": "Restricted Area"} raise Unauthorized("Auth required.", "Bearer")
raise Unauthorized("Auth required.", "Bearer", challenge)
# or, if you want to specify the realm:
raise Unauthorized("Auth required.", "Bearer", realm="Restricted Area")
""" """
pass def __init__(self, message, scheme, **kwargs):
def __init__(self, message, scheme, challenge=None):
super().__init__(message) super().__init__(message)
chal = "" values = ["{!s}={!r}".format(k, v) for k, v in kwargs.items()]
challenge = ', '.join(values)
if challenge is not None:
values = ["{!s}={!r}".format(k, v) for k, v in challenge.items()]
chal = ', '.join(values)
self.headers = { self.headers = {
"WWW-Authenticate": "{} {}".format(scheme, chal).rstrip() "WWW-Authenticate": "{} {}".format(scheme, challenge).rstrip()
} }

View File

@ -33,18 +33,17 @@ def exception_app():
@app.route('/401/basic') @app.route('/401/basic')
def handler_401_basic(request): def handler_401_basic(request):
raise Unauthorized("Unauthorized", "Basic", {"realm": "Sanic"}) raise Unauthorized("Unauthorized", "Basic", realm="Sanic")
@app.route('/401/digest') @app.route('/401/digest')
def handler_401_digest(request): def handler_401_digest(request):
challenge = { raise Unauthorized("Unauthorized",
"realm": "Sanic", "Digest",
"qop": "auth, auth-int", realm="Sanic",
"algorithm": "MD5", qop="auth, auth-int",
"nonce": "abcdef", algorithm="MD5",
"opaque": "zyxwvu", nonce="abcdef",
} opaque="zyxwvu")
raise Unauthorized("Unauthorized", "Digest", challenge)
@app.route('/401/bearer') @app.route('/401/bearer')
def handler_401_bearer(request): def handler_401_bearer(request):
@ -122,7 +121,7 @@ def test_forbidden_exception(exception_app):
request, response = exception_app.test_client.get('/403') request, response = exception_app.test_client.get('/403')
assert response.status == 403 assert response.status == 403
def test_unauthorized_exception(exception_app): def test_unauthorized_exception(exception_app):
"""Test the built-in Unauthorized exception""" """Test the built-in Unauthorized exception"""
request, response = exception_app.test_client.get('/401/basic') request, response = exception_app.test_client.get('/401/basic')
@ -132,7 +131,7 @@ def test_unauthorized_exception(exception_app):
request, response = exception_app.test_client.get('/401/digest') request, response = exception_app.test_client.get('/401/digest')
assert response.status == 401 assert response.status == 401
auth_header = response.headers.get('WWW-Authenticate') auth_header = response.headers.get('WWW-Authenticate')
assert auth_header is not None assert auth_header is not None
assert auth_header.startswith('Digest') assert auth_header.startswith('Digest')

View File

@ -1,5 +1,7 @@
import asyncio
import uuid import uuid
from importlib import reload
from sanic.config import LOGGING
from sanic.response import text from sanic.response import text
from sanic import Sanic from sanic import Sanic
from io import StringIO from io import StringIO
@ -10,6 +12,11 @@ function: %(funcName)s(); \
message: %(message)s''' message: %(message)s'''
def reset_logging():
logging.shutdown()
reload(logging)
def test_log(): def test_log():
log_stream = StringIO() log_stream = StringIO()
for handler in logging.root.handlers[:]: for handler in logging.root.handlers[:]:
@ -32,5 +39,19 @@ def test_log():
log_text = log_stream.getvalue() log_text = log_stream.getvalue()
assert rand_string in log_text assert rand_string in log_text
def test_default_log_fmt():
reset_logging()
Sanic()
for fmt in [h.formatter for h in logging.getLogger('sanic').handlers]:
assert fmt._fmt == LOGGING['formatters']['simple']['format']
reset_logging()
Sanic(log_config=None)
for fmt in [h.formatter for h in logging.getLogger('sanic').handlers]:
assert fmt._fmt == "%(asctime)s: %(levelname)s: %(message)s"
if __name__ == "__main__": if __name__ == "__main__":
test_log() test_log()