Compare commits
	
		
			30 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 1036242064 | ||
|   | 5fd62098bd | ||
|   | b3814ca89a | ||
|   | b75a321e4a | ||
|   | 9caa4fec4a | ||
|   | a0cba1aee1 | ||
|   | 97018ad62f | ||
|   | a7d17fae44 | ||
|   | 6ce0050979 | ||
|   | bc035fca78 | ||
|   | df914a92e4 | ||
|   | 1b939a6823 | ||
|   | 81b6d988ec | ||
|   | 7e9b65feca | ||
|   | 6f098b3d21 | ||
|   | 5ddb0488f2 | ||
|   | 3e87314adf | ||
|   | f6d4a06661 | ||
|   | ff17fc95e6 | ||
|   | c5a46f1cea | ||
|   | 0b072189c4 | ||
|   | 5b22d1486a | ||
|   | 9eb48c2b0d | ||
|   | ff0632001c | ||
|   | 28bd09a2ea | ||
|   | c6aaa9b09c | ||
|   | 20d9ec1fd2 | ||
|   | 2c45c2d3c0 | ||
|   | 4c66cb1854 | ||
|   | 35b92e1511 | 
							
								
								
									
										62
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | # Contributing | ||||||
|  |  | ||||||
|  | Thank you for your interest! Sanic is always looking for contributors. If you | ||||||
|  | don't feel comfortable contributing code, adding docstrings to the source files | ||||||
|  | is very appreciated. | ||||||
|  |  | ||||||
|  | ## Installation | ||||||
|  |  | ||||||
|  | To develop on sanic (and mainly to just run the tests) it is highly recommend to | ||||||
|  | install from sources. | ||||||
|  |  | ||||||
|  | So assume you have already cloned the repo and are in the working directory with | ||||||
|  | a virtual environment already set up, then run: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | python setup.py develop && pip install -r requirements-dev.txt | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Running tests | ||||||
|  |  | ||||||
|  | To run the tests for sanic it is recommended to use tox like so: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | tox | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | See it's that simple! | ||||||
|  |  | ||||||
|  | ## Pull requests! | ||||||
|  |  | ||||||
|  | So the pull request approval rules are pretty simple: | ||||||
|  | 1. All pull requests must pass unit tests | ||||||
|  | 2. All pull requests must be reviewed and approved by at least  | ||||||
|  | one current collaborator on the project | ||||||
|  | 3. All pull requests must pass flake8 checks | ||||||
|  | 4. If you decide to remove/change anything from any common interface | ||||||
|  | a deprecation message should accompany it. | ||||||
|  | 5. If you implement a new feature you should have at least one unit | ||||||
|  | test to accompany it. | ||||||
|  |  | ||||||
|  | ## Documentation | ||||||
|  |  | ||||||
|  | Sanic's documentation is built | ||||||
|  | using [sphinx](http://www.sphinx-doc.org/en/1.5.1/). Guides are written in | ||||||
|  | Markdown and can be found in the `docs` folder, while the module reference is | ||||||
|  | automatically generated using `sphinx-apidoc`. | ||||||
|  |  | ||||||
|  | To generate the documentation from scratch: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | sphinx-apidoc -fo docs/_api/ sanic | ||||||
|  | sphinx-build -b html docs docs/_build | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | The HTML documentation will be created in the `docs/_build` folder. | ||||||
|  |  | ||||||
|  | ## Warning | ||||||
|  |  | ||||||
|  | One of the main goals of Sanic is speed. Code that lowers the performance of | ||||||
|  | Sanic without significant gains in usability, security, or features may not be | ||||||
|  | merged. Please don't let this intimidate you! If you have any concerns about an | ||||||
|  | idea, open an issue for discussion and help. | ||||||
| @@ -83,3 +83,4 @@ Out of the box there are just a few predefined values which can be overwritten w | |||||||
|     | ----------------- | --------- | --------------------------------- | |     | ----------------- | --------- | --------------------------------- | | ||||||
|     | REQUEST_MAX_SIZE  | 100000000 | How big a request may be (bytes)  | |     | REQUEST_MAX_SIZE  | 100000000 | How big a request may be (bytes)  | | ||||||
|     | REQUEST_TIMEOUT   | 60        | How long a request can take (sec) | |     | REQUEST_TIMEOUT   | 60        | How long a request can take (sec) | | ||||||
|  |     | KEEP_ALIVE        | True      | Disables keep-alive when False    | | ||||||
|   | |||||||
| @@ -4,10 +4,39 @@ Thank you for your interest! Sanic is always looking for contributors. If you | |||||||
| don't feel comfortable contributing code, adding docstrings to the source files | don't feel comfortable contributing code, adding docstrings to the source files | ||||||
| is very appreciated. | is very appreciated. | ||||||
|  |  | ||||||
|  | ## Installation | ||||||
|  |  | ||||||
|  | To develop on sanic (and mainly to just run the tests) it is highly recommend to | ||||||
|  | install from sources. | ||||||
|  |  | ||||||
|  | So assume you have already cloned the repo and are in the working directory with | ||||||
|  | a virtual environment already set up, then run: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | python setup.py develop && pip install -r requirements-dev.txt | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## Running tests | ## Running tests | ||||||
|  |  | ||||||
| * `python -m pip install pytest` | To run the tests for sanic it is recommended to use tox like so: | ||||||
| * `python -m pytest tests` |  | ||||||
|  | ```bash | ||||||
|  | tox | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | See it's that simple! | ||||||
|  |  | ||||||
|  | ## Pull requests! | ||||||
|  |  | ||||||
|  | So the pull request approval rules are pretty simple: | ||||||
|  | 1. All pull requests must pass unit tests | ||||||
|  | * All pull requests must be reviewed and approved by at least  | ||||||
|  | one current collaborator on the project | ||||||
|  | * All pull requests must pass flake8 checks | ||||||
|  | * If you decide to remove/change anything from any common interface | ||||||
|  | a deprecation message should accompany it. | ||||||
|  | * If you implement a new feature you should have at least one unit | ||||||
|  | test to accompany it. | ||||||
|  |  | ||||||
| ## Documentation | ## Documentation | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								examples/dask_distributed.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								examples/dask_distributed.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | from sanic import Sanic | ||||||
|  | from sanic import response | ||||||
|  |  | ||||||
|  | from tornado.platform.asyncio import BaseAsyncIOLoop, to_asyncio_future | ||||||
|  | from distributed import LocalCluster, Client | ||||||
|  |  | ||||||
|  |  | ||||||
|  | app = Sanic(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def square(x): | ||||||
|  |     return x**2 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.listener('after_server_start') | ||||||
|  | async def setup(app, loop): | ||||||
|  |     # configure tornado use asyncio's loop | ||||||
|  |     ioloop = BaseAsyncIOLoop(loop) | ||||||
|  |  | ||||||
|  |     # init distributed client | ||||||
|  |     app.client = Client('tcp://localhost:8786', loop=ioloop, start=False) | ||||||
|  |     await to_asyncio_future(app.client._start()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.listener('before_server_stop') | ||||||
|  | async def stop(app, loop): | ||||||
|  |     await to_asyncio_future(app.client._shutdown()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.route('/<value:int>') | ||||||
|  | async def test(request, value): | ||||||
|  |     future = app.client.submit(square, value) | ||||||
|  |     result = await to_asyncio_future(future._result()) | ||||||
|  |     return response.text(f'The square of {value} is {result}') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     # Distributed cluster should run somewhere else | ||||||
|  |     with LocalCluster(scheduler_port=8786, nanny=False, n_workers=2, | ||||||
|  |                       threads_per_worker=1) as cluster: | ||||||
|  |         app.run(host="0.0.0.0", port=8000) | ||||||
| @@ -1,18 +1,27 @@ | |||||||
| ## To use this example: | # Render templates in a Flask like way from a "template" directory in the project | ||||||
| # curl -d '{"name": "John Doe"}' localhost:8000 |  | ||||||
|  |  | ||||||
| from sanic import Sanic | from sanic import Sanic | ||||||
| from sanic import response | from sanic import response | ||||||
| from jinja2 import Template | from jinja2 import Evironment, PackageLoader, select_autoescape | ||||||
|  |  | ||||||
| template = Template('Hello {{ name }}!') |  | ||||||
|  |  | ||||||
| app = Sanic(__name__) | app = Sanic(__name__) | ||||||
|  |  | ||||||
|  | # Load the template environment with async support | ||||||
|  | template_env = Environment( | ||||||
|  |     loader=jinja2.PackageLoader('yourapplication', 'templates'), | ||||||
|  |     autoescape=jinja2.select_autoescape(['html', 'xml']), | ||||||
|  |     enable_async=True | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # Load the template from file | ||||||
|  | template = template_env.get_template("example_template.html") | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.route('/') | @app.route('/') | ||||||
| async def test(request): | async def test(request): | ||||||
|     data = request.json |     data = request.json | ||||||
|     return response.html(template.render(**data)) |     rendered_template = await template.render_async(**data) | ||||||
|  |     return response.html(rendered_template) | ||||||
|  |  | ||||||
|  |  | ||||||
| app.run(host="0.0.0.0", port=8080, debug=True) | app.run(host="0.0.0.0", port=8080, debug=True) | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| from sanic.app import Sanic | from sanic.app import Sanic | ||||||
| from sanic.blueprints import Blueprint | from sanic.blueprints import Blueprint | ||||||
|  |  | ||||||
| __version__ = '0.5.1' | __version__ = '0.5.2' | ||||||
|  |  | ||||||
| __all__ = ['Sanic', 'Blueprint'] | __all__ = ['Sanic', 'Blueprint'] | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ from sanic.handlers import ErrorHandler | |||||||
| from sanic.log import log | from sanic.log import log | ||||||
| from sanic.response import HTTPResponse, StreamingHTTPResponse | from sanic.response import HTTPResponse, StreamingHTTPResponse | ||||||
| from sanic.router import Router | from sanic.router import Router | ||||||
| from sanic.server import serve, serve_multiple, HttpProtocol | from sanic.server import serve, serve_multiple, HttpProtocol, Signal | ||||||
| from sanic.static import register as static_register | from sanic.static import register as static_register | ||||||
| from sanic.testing import SanicTestClient | from sanic.testing import SanicTestClient | ||||||
| from sanic.views import CompositionView | from sanic.views import CompositionView | ||||||
| @@ -288,7 +288,7 @@ class Sanic: | |||||||
|                            attach_to=middleware_or_request) |                            attach_to=middleware_or_request) | ||||||
|  |  | ||||||
|     # Static Files |     # Static Files | ||||||
|     def static(self, uri, file_or_directory, pattern='.+', |     def static(self, uri, file_or_directory, pattern=r'/?.+', | ||||||
|                use_modified_since=True, use_content_range=False): |                use_modified_since=True, use_content_range=False): | ||||||
|         """Register a root to serve files from. The input can either be a |         """Register a root to serve files from. The input can either be a | ||||||
|         file or a directory. See |         file or a directory. See | ||||||
| @@ -674,11 +674,13 @@ class Sanic: | |||||||
|             'port': port, |             'port': port, | ||||||
|             'sock': sock, |             'sock': sock, | ||||||
|             'ssl': ssl, |             'ssl': ssl, | ||||||
|  |             'signal': Signal(), | ||||||
|             'debug': debug, |             'debug': debug, | ||||||
|             'request_handler': self.handle_request, |             'request_handler': self.handle_request, | ||||||
|             'error_handler': self.error_handler, |             'error_handler': self.error_handler, | ||||||
|             'request_timeout': self.config.REQUEST_TIMEOUT, |             'request_timeout': self.config.REQUEST_TIMEOUT, | ||||||
|             'request_max_size': self.config.REQUEST_MAX_SIZE, |             'request_max_size': self.config.REQUEST_MAX_SIZE, | ||||||
|  |             'keep_alive': self.config.KEEP_ALIVE, | ||||||
|             'loop': loop, |             'loop': loop, | ||||||
|             'register_sys_signals': register_sys_signals, |             'register_sys_signals': register_sys_signals, | ||||||
|             'backlog': backlog |             'backlog': backlog | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ SANIC_PREFIX = 'SANIC_' | |||||||
|  |  | ||||||
|  |  | ||||||
| class Config(dict): | class Config(dict): | ||||||
|     def __init__(self, defaults=None, load_env=True): |     def __init__(self, defaults=None, load_env=True, keep_alive=True): | ||||||
|         super().__init__(defaults or {}) |         super().__init__(defaults or {}) | ||||||
|         self.LOGO = """ |         self.LOGO = """ | ||||||
|                  ▄▄▄▄▄ |                  ▄▄▄▄▄ | ||||||
| @@ -31,6 +31,7 @@ class Config(dict): | |||||||
| """ | """ | ||||||
|         self.REQUEST_MAX_SIZE = 100000000  # 100 megababies |         self.REQUEST_MAX_SIZE = 100000000  # 100 megababies | ||||||
|         self.REQUEST_TIMEOUT = 60  # 60 seconds |         self.REQUEST_TIMEOUT = 60  # 60 seconds | ||||||
|  |         self.KEEP_ALIVE = keep_alive | ||||||
|  |  | ||||||
|         if load_env: |         if load_env: | ||||||
|             self.load_environment_vars() |             self.load_environment_vars() | ||||||
| @@ -98,11 +99,11 @@ class Config(dict): | |||||||
|                 self[key] = getattr(obj, key) |                 self[key] = getattr(obj, key) | ||||||
|  |  | ||||||
|     def load_environment_vars(self): |     def load_environment_vars(self): | ||||||
|  |         """ | ||||||
|  |         Looks for any SANIC_ prefixed environment variables and applies | ||||||
|  |         them to the configuration if present. | ||||||
|  |         """ | ||||||
|         for k, v in os.environ.items(): |         for k, v in os.environ.items(): | ||||||
|             """ |  | ||||||
|             Looks for any SANIC_ prefixed environment variables and applies |  | ||||||
|             them to the configuration if present. |  | ||||||
|             """ |  | ||||||
|             if k.startswith(SANIC_PREFIX): |             if k.startswith(SANIC_PREFIX): | ||||||
|                 _, config_key = k.split(SANIC_PREFIX, 1) |                 _, config_key = k.split(SANIC_PREFIX, 1) | ||||||
|                 self[config_key] = v |                 self[config_key] = v | ||||||
|   | |||||||
| @@ -78,9 +78,10 @@ class Request(dict): | |||||||
|         :return: token related to request |         :return: token related to request | ||||||
|         """ |         """ | ||||||
|         auth_header = self.headers.get('Authorization') |         auth_header = self.headers.get('Authorization') | ||||||
|         if auth_header is not None: |         if 'Token ' in auth_header: | ||||||
|             return auth_header.split()[1] |             return auth_header.partition('Token ')[-1] | ||||||
|         return auth_header |         else: | ||||||
|  |             return auth_header | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def form(self): |     def form(self): | ||||||
|   | |||||||
| @@ -210,7 +210,7 @@ class HTTPResponse(BaseHTTPResponse): | |||||||
|         # Speeds up response rate 6% over pulling from all |         # Speeds up response rate 6% over pulling from all | ||||||
|         status = COMMON_STATUS_CODES.get(self.status) |         status = COMMON_STATUS_CODES.get(self.status) | ||||||
|         if not status: |         if not status: | ||||||
|             status = ALL_STATUS_CODES.get(self.status) |             status = ALL_STATUS_CODES.get(self.status, b'UNKNOWN RESPONSE') | ||||||
|  |  | ||||||
|         return (b'HTTP/%b %d %b\r\n' |         return (b'HTTP/%b %d %b\r\n' | ||||||
|                 b'Connection: %b\r\n' |                 b'Connection: %b\r\n' | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ REGEX_TYPES = { | |||||||
|     'int': (int, r'\d+'), |     'int': (int, r'\d+'), | ||||||
|     'number': (float, r'[0-9\\.]+'), |     'number': (float, r'[0-9\\.]+'), | ||||||
|     'alpha': (str, r'[A-Za-z]+'), |     'alpha': (str, r'[A-Za-z]+'), | ||||||
|  |     'path': (str, r'[^/].*?'), | ||||||
| } | } | ||||||
|  |  | ||||||
| ROUTER_CACHE_SIZE = 1024 | ROUTER_CACHE_SIZE = 1024 | ||||||
| @@ -71,7 +72,8 @@ class Router: | |||||||
|         self.routes_always_check = [] |         self.routes_always_check = [] | ||||||
|         self.hosts = set() |         self.hosts = set() | ||||||
|  |  | ||||||
|     def parse_parameter_string(self, parameter_string): |     @classmethod | ||||||
|  |     def parse_parameter_string(cls, parameter_string): | ||||||
|         """Parse a parameter string into its constituent name, type, and |         """Parse a parameter string into its constituent name, type, and | ||||||
|         pattern |         pattern | ||||||
|  |  | ||||||
| @@ -161,10 +163,10 @@ class Router: | |||||||
|             parameters.append(parameter) |             parameters.append(parameter) | ||||||
|  |  | ||||||
|             # Mark the whole route as unhashable if it has the hash key in it |             # Mark the whole route as unhashable if it has the hash key in it | ||||||
|             if re.search('(^|[^^]){1}/', pattern): |             if re.search(r'(^|[^^]){1}/', pattern): | ||||||
|                 properties['unhashable'] = True |                 properties['unhashable'] = True | ||||||
|             # Mark the route as unhashable if it matches the hash key |             # Mark the route as unhashable if it matches the hash key | ||||||
|             elif re.search(pattern, '/'): |             elif re.search(r'/', pattern): | ||||||
|                 properties['unhashable'] = True |                 properties['unhashable'] = True | ||||||
|  |  | ||||||
|             return '({})'.format(pattern) |             return '({})'.format(pattern) | ||||||
|   | |||||||
| @@ -70,7 +70,8 @@ class HttpProtocol(asyncio.Protocol): | |||||||
|  |  | ||||||
|     def __init__(self, *, loop, request_handler, error_handler, |     def __init__(self, *, loop, request_handler, error_handler, | ||||||
|                  signal=Signal(), connections=set(), request_timeout=60, |                  signal=Signal(), connections=set(), request_timeout=60, | ||||||
|                  request_max_size=None, request_class=None): |                  request_max_size=None, request_class=None, | ||||||
|  |                  keep_alive=True): | ||||||
|         self.loop = loop |         self.loop = loop | ||||||
|         self.transport = None |         self.transport = None | ||||||
|         self.request = None |         self.request = None | ||||||
| @@ -88,10 +89,13 @@ class HttpProtocol(asyncio.Protocol): | |||||||
|         self._timeout_handler = None |         self._timeout_handler = None | ||||||
|         self._last_request_time = None |         self._last_request_time = None | ||||||
|         self._request_handler_task = None |         self._request_handler_task = None | ||||||
|  |         self._keep_alive = keep_alive | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def keep_alive(self): |     def keep_alive(self): | ||||||
|         return self.parser.should_keep_alive() and not self.signal.stopped |         return (self._keep_alive | ||||||
|  |                 and not self.signal.stopped | ||||||
|  |                 and self.parser.should_keep_alive()) | ||||||
|  |  | ||||||
|     # -------------------------------------------- # |     # -------------------------------------------- # | ||||||
|     # Connection |     # Connection | ||||||
| @@ -322,7 +326,7 @@ def serve(host, port, request_handler, error_handler, before_start=None, | |||||||
|           request_timeout=60, ssl=None, sock=None, request_max_size=None, |           request_timeout=60, ssl=None, sock=None, request_max_size=None, | ||||||
|           reuse_port=False, loop=None, protocol=HttpProtocol, backlog=100, |           reuse_port=False, loop=None, protocol=HttpProtocol, backlog=100, | ||||||
|           register_sys_signals=True, run_async=False, connections=None, |           register_sys_signals=True, run_async=False, connections=None, | ||||||
|           signal=Signal(), request_class=None): |           signal=Signal(), request_class=None, keep_alive=True): | ||||||
|     """Start asynchronous HTTP Server on an individual process. |     """Start asynchronous HTTP Server on an individual process. | ||||||
|  |  | ||||||
|     :param host: Address to host on |     :param host: Address to host on | ||||||
| @@ -370,6 +374,7 @@ def serve(host, port, request_handler, error_handler, before_start=None, | |||||||
|         request_timeout=request_timeout, |         request_timeout=request_timeout, | ||||||
|         request_max_size=request_max_size, |         request_max_size=request_max_size, | ||||||
|         request_class=request_class, |         request_class=request_class, | ||||||
|  |         keep_alive=keep_alive, | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     server_coroutine = loop.create_server( |     server_coroutine = loop.create_server( | ||||||
|   | |||||||
| @@ -56,7 +56,7 @@ def register(app, uri, file_or_directory, pattern, | |||||||
|         # URL decode the path sent by the browser otherwise we won't be able to |         # URL decode the path sent by the browser otherwise we won't be able to | ||||||
|         # match filenames which got encoded (filenames with spaces etc) |         # match filenames which got encoded (filenames with spaces etc) | ||||||
|         file_path = path.abspath(unquote(file_path)) |         file_path = path.abspath(unquote(file_path)) | ||||||
|         if not file_path.startswith(root_path): |         if not file_path.startswith(path.abspath(unquote(root_path))): | ||||||
|             raise FileNotFound('File not found', |             raise FileNotFound('File not found', | ||||||
|                                path=file_or_directory, |                                path=file_or_directory, | ||||||
|                                relative_url=file_uri) |                                relative_url=file_uri) | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import sys | |||||||
| import signal | import signal | ||||||
| import asyncio | import asyncio | ||||||
| import logging | import logging | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     import ssl |     import ssl | ||||||
| except ImportError: | except ImportError: | ||||||
| @@ -50,8 +51,8 @@ class GunicornWorker(base.Worker): | |||||||
|             debug=is_debug, |             debug=is_debug, | ||||||
|             protocol=protocol, |             protocol=protocol, | ||||||
|             ssl=self.ssl_context, |             ssl=self.ssl_context, | ||||||
|             run_async=True |             run_async=True) | ||||||
|         ) |         self._server_settings['signal'] = self.signal | ||||||
|         self._server_settings.pop('sock') |         self._server_settings.pop('sock') | ||||||
|         trigger_events(self._server_settings.get('before_start', []), |         trigger_events(self._server_settings.get('before_start', []), | ||||||
|                        self.loop) |                        self.loop) | ||||||
| @@ -97,7 +98,6 @@ class GunicornWorker(base.Worker): | |||||||
|             self.servers.append(await serve( |             self.servers.append(await serve( | ||||||
|                 sock=sock, |                 sock=sock, | ||||||
|                 connections=self.connections, |                 connections=self.connections, | ||||||
|                 signal=self.signal, |  | ||||||
|                 **self._server_settings |                 **self._server_settings | ||||||
|             )) |             )) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -141,6 +141,16 @@ def test_token(): | |||||||
|         return text('OK') |         return text('OK') | ||||||
|  |  | ||||||
|     # uuid4 generated token. |     # uuid4 generated token. | ||||||
|  |     token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' | ||||||
|  |     headers = { | ||||||
|  |         'content-type': 'application/json', | ||||||
|  |         'Authorization': '{}'.format(token) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     request, response = app.test_client.get('/', headers=headers) | ||||||
|  |  | ||||||
|  |     assert request.token == token | ||||||
|  |  | ||||||
|     token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' |     token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' | ||||||
|     headers = { |     headers = { | ||||||
|         'content-type': 'application/json', |         'content-type': 'application/json', | ||||||
| @@ -151,6 +161,18 @@ def test_token(): | |||||||
|  |  | ||||||
|     assert request.token == token |     assert request.token == token | ||||||
|  |  | ||||||
|  |     token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' | ||||||
|  |     headers = { | ||||||
|  |         'content-type': 'application/json', | ||||||
|  |         'Authorization': 'Bearer Token {}'.format(token) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     request, response = app.test_client.get('/', headers=headers) | ||||||
|  |  | ||||||
|  |     assert request.token == token | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # ------------------------------------------------------------ # | # ------------------------------------------------------------ # | ||||||
| #  POST | #  POST | ||||||
| # ------------------------------------------------------------ # | # ------------------------------------------------------------ # | ||||||
|   | |||||||
| @@ -238,6 +238,30 @@ def test_dynamic_route_regex(): | |||||||
|     assert response.status == 200 |     assert response.status == 200 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_dynamic_route_path(): | ||||||
|  |     app = Sanic('test_dynamic_route_path') | ||||||
|  |  | ||||||
|  |     @app.route('/<path:path>/info') | ||||||
|  |     async def handler(request, path): | ||||||
|  |         return text('OK') | ||||||
|  |  | ||||||
|  |     request, response = app.test_client.get('/path/1/info') | ||||||
|  |     assert response.status == 200 | ||||||
|  |  | ||||||
|  |     request, response = app.test_client.get('/info') | ||||||
|  |     assert response.status == 404 | ||||||
|  |  | ||||||
|  |     @app.route('/<path:path>') | ||||||
|  |     async def handler1(request, path): | ||||||
|  |         return text('OK') | ||||||
|  |  | ||||||
|  |     request, response = app.test_client.get('/info') | ||||||
|  |     assert response.status == 200 | ||||||
|  |  | ||||||
|  |     request, response = app.test_client.get('/whatever/you/set') | ||||||
|  |     assert response.status == 200 | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_dynamic_route_unhashable(): | def test_dynamic_route_unhashable(): | ||||||
|     app = Sanic('test_dynamic_route_unhashable') |     app = Sanic('test_dynamic_route_unhashable') | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user