merge master into local branch
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -14,3 +14,4 @@ settings.py | ||||
| docs/_build/ | ||||
| docs/_api/ | ||||
| build/* | ||||
| .DS_Store | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| sudo: false | ||||
| dist: precise | ||||
| language: python | ||||
| cache: | ||||
|   directories: | ||||
|   | ||||
							
								
								
									
										10
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.rst
									
									
									
									
									
								
							| @@ -56,6 +56,16 @@ Documentation | ||||
| .. |PyPI version| image:: https://img.shields.io/pypi/pyversions/sanic.svg | ||||
|    :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 | ||||
| ---- | ||||
|  * http2 | ||||
|   | ||||
| @@ -59,7 +59,7 @@ the available arguments to aiohttp can be found | ||||
| [in the documentation for ClientSession](https://aiohttp.readthedocs.io/en/stable/client_reference.html#client-session). | ||||
|  | ||||
|  | ||||
| # pytest-sanic | ||||
| ## pytest-sanic | ||||
|  | ||||
| [pytest-sanic](https://github.com/yunstanford/pytest-sanic) is a pytest plugin, it helps you to test your code asynchronously. | ||||
| Just write tests like, | ||||
|   | ||||
| @@ -10,11 +10,11 @@ You can pass a version number to the routes directly. | ||||
| from sanic import response | ||||
|  | ||||
|  | ||||
| @app.route('/text', verion=1) | ||||
| @app.route('/text', version=1) | ||||
| def handle_request(request): | ||||
|     return response.text('Hello world! Version 1') | ||||
|  | ||||
| @app.route('/text', verion=2) | ||||
| @app.route('/text', version=2) | ||||
| def handle_request(request): | ||||
|     return response.text('Hello world! Version 2') | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| from sanic.app import Sanic | ||||
| from sanic.blueprints import Blueprint | ||||
|  | ||||
| __version__ = '0.5.4' | ||||
| __version__ = '0.6.0' | ||||
|  | ||||
| __all__ = ['Sanic', 'Blueprint'] | ||||
|   | ||||
| @@ -33,9 +33,7 @@ class Sanic: | ||||
|             logging.config.dictConfig(log_config) | ||||
|         # Only set up a default log handler if the | ||||
|         # end-user application didn't set anything up. | ||||
|         if not (logging.root.handlers and | ||||
|                 log.level == logging.NOTSET and | ||||
|                 log_config): | ||||
|         if not logging.root.handlers and log.level == logging.NOTSET: | ||||
|             formatter = logging.Formatter( | ||||
|                 "%(asctime)s: %(levelname)s: %(message)s") | ||||
|             handler = logging.StreamHandler() | ||||
|   | ||||
| @@ -208,44 +208,39 @@ class Unauthorized(SanicException): | ||||
|     """ | ||||
|     Unauthorized exception (401 HTTP status code). | ||||
|  | ||||
|     :param message: Message describing the exception. | ||||
|     :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 | ||||
|         the Digest scheme. (optional) | ||||
|  | ||||
|     When present, kwargs is used to complete the WWW-Authentication header. | ||||
|  | ||||
|     Examples:: | ||||
|  | ||||
|         # With a Basic auth-scheme, realm MUST be present: | ||||
|         challenge = {"realm": "Restricted Area"} | ||||
|         raise Unauthorized("Auth required.", "Basic", challenge) | ||||
|         raise Unauthorized("Auth required.", "Basic", realm="Restricted Area") | ||||
|  | ||||
|         # With a Digest auth-scheme, things are a bit more complicated: | ||||
|         challenge = { | ||||
|             "realm": "Restricted Area", | ||||
|             "qop": "auth, auth-int", | ||||
|             "algorithm": "MD5", | ||||
|             "nonce": "abcdef", | ||||
|             "opaque": "zyxwvu" | ||||
|         } | ||||
|         raise Unauthorized("Auth required.", "Digest", challenge) | ||||
|         raise Unauthorized("Auth required.", | ||||
|                            "Digest", | ||||
|                            realm="Restricted Area", | ||||
|                            qop="auth, auth-int", | ||||
|                            algorithm="MD5", | ||||
|                            nonce="abcdef", | ||||
|                            opaque="zyxwvu") | ||||
|  | ||||
|         # With a Bearer auth-scheme, realm is optional: | ||||
|         challenge = {"realm": "Restricted Area"} | ||||
|         raise Unauthorized("Auth required.", "Bearer", challenge) | ||||
|         # With a Bearer auth-scheme, realm is optional so you can write: | ||||
|         raise Unauthorized("Auth required.", "Bearer") | ||||
|  | ||||
|         # or, if you want to specify the realm: | ||||
|         raise Unauthorized("Auth required.", "Bearer", realm="Restricted Area") | ||||
|     """ | ||||
|     pass | ||||
|  | ||||
|     def __init__(self, message, scheme, challenge=None): | ||||
|     def __init__(self, message, scheme, **kwargs): | ||||
|         super().__init__(message) | ||||
|  | ||||
|         chal = "" | ||||
|  | ||||
|         if challenge is not None: | ||||
|             values = ["{!s}={!r}".format(k, v) for k, v in challenge.items()] | ||||
|             chal = ', '.join(values) | ||||
|         values = ["{!s}={!r}".format(k, v) for k, v in kwargs.items()] | ||||
|         challenge = ', '.join(values) | ||||
|  | ||||
|         self.headers = { | ||||
|             "WWW-Authenticate": "{} {}".format(scheme, chal).rstrip() | ||||
|             "WWW-Authenticate": "{} {}".format(scheme, challenge).rstrip() | ||||
|         } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -33,18 +33,17 @@ def exception_app(): | ||||
|  | ||||
|     @app.route('/401/basic') | ||||
|     def handler_401_basic(request): | ||||
|         raise Unauthorized("Unauthorized", "Basic", {"realm": "Sanic"}) | ||||
|         raise Unauthorized("Unauthorized", "Basic", realm="Sanic") | ||||
|  | ||||
|     @app.route('/401/digest') | ||||
|     def handler_401_digest(request): | ||||
|         challenge = { | ||||
|             "realm": "Sanic", | ||||
|             "qop": "auth, auth-int", | ||||
|             "algorithm": "MD5", | ||||
|             "nonce": "abcdef", | ||||
|             "opaque": "zyxwvu", | ||||
|         } | ||||
|         raise Unauthorized("Unauthorized", "Digest", challenge) | ||||
|         raise Unauthorized("Unauthorized", | ||||
|                            "Digest", | ||||
|                            realm="Sanic", | ||||
|                            qop="auth, auth-int", | ||||
|                            algorithm="MD5", | ||||
|                            nonce="abcdef", | ||||
|                            opaque="zyxwvu") | ||||
|  | ||||
|     @app.route('/401/bearer') | ||||
|     def handler_401_bearer(request): | ||||
|   | ||||
| @@ -24,7 +24,7 @@ def handler_3(request): | ||||
|  | ||||
| @exception_handler_app.route('/4') | ||||
| def handler_4(request): | ||||
|     foo = bar | ||||
|     foo = bar    # noqa -- F821 undefined name 'bar' is done to throw exception | ||||
|     return text(foo) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| import asyncio | ||||
| import uuid | ||||
| from importlib import reload | ||||
|  | ||||
| from sanic.config import LOGGING | ||||
| from sanic.response import text | ||||
| from sanic import Sanic | ||||
| from io import StringIO | ||||
| @@ -10,6 +12,11 @@ function: %(funcName)s(); \ | ||||
| message: %(message)s''' | ||||
|  | ||||
|  | ||||
| def reset_logging(): | ||||
|     logging.shutdown() | ||||
|     reload(logging) | ||||
|  | ||||
|  | ||||
| def test_log(): | ||||
|     log_stream = StringIO() | ||||
|     for handler in logging.root.handlers[:]: | ||||
| @@ -32,5 +39,19 @@ def test_log(): | ||||
|     log_text = log_stream.getvalue() | ||||
|     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__": | ||||
|     test_log() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 MichaelYusko
					MichaelYusko