Add Router, Path, PathPrefix

This commit is contained in:
Tom Christie 2018-06-25 22:23:40 +01:00
parent 5ab86e1522
commit 903e1b2fc5
3 changed files with 108 additions and 0 deletions

View File

@ -1,6 +1,7 @@
from starlette.decorators import asgi_application
from starlette.response import HTMLResponse, JSONResponse, Response, StreamingResponse
from starlette.request import Request
from starlette.routing import Path, PathPrefix, Router
from starlette.testclient import TestClient

64
starlette/routing.py Normal file
View File

@ -0,0 +1,64 @@
from starlette import Response
import re
class Path:
def __init__(self, path, app):
self.path = path
self.app = app
regex = '^' + path + '$'
regex = re.sub('{([a-zA-Z_][a-zA-Z0-9_]*)}', r'(?P<\1>[^/]*)', regex)
self.path_regex = re.compile(regex)
def matches(self, scope):
match = self.path_regex.match(scope['path'])
if match:
kwargs = dict(scope.get('kwargs', {}))
kwargs.update(match.groupdict())
child_scope = scope.copy()
child_scope['kwargs'] = kwargs
return True, child_scope
return False, {}
def __call__(self, scope):
return self.app(scope)
class PathPrefix:
def __init__(self, path, app):
self.path = path
self.app = app
regex = '^' + path
regex = re.sub('{([a-zA-Z_][a-zA-Z0-9_]*)}', r'(?P<\1>[^/]*)', regex)
self.path_regex = re.compile(regex)
def matches(self, scope):
match = self.path_regex.match(scope['path'])
if match:
kwargs = dict(scope.get('kwargs', {}))
kwargs.update(match.groupdict())
child_scope = scope.copy()
child_scope['kwargs'] = kwargs
child_scope['root_path'] = scope.get('root_path', '') + match.string
child_scope['path'] = scope['path'][match.span()[1]:]
return True, child_scope
return False, {}
def __call__(self, scope):
return self.app(scope)
class Router:
def __init__(self, routes, default=None):
self.routes = routes
self.default = self.not_found if default is None else default
def __call__(self, scope):
for route in self.routes:
matched, child_scope = route.matches(scope)
if matched:
return route(child_scope)
return self.not_found(scope)
def not_found(self, scope):
return Response('Not found', 404, media_type='text/plain')

43
tests/test_routing.py Normal file
View File

@ -0,0 +1,43 @@
from starlette import Response, Path, PathPrefix, Router, TestClient
def homepage(scope):
return Response('Hello, world', media_type='text/plain')
def users(scope):
return Response('All users', media_type='text/plain')
def user(scope):
content = 'User ' + scope['kwargs']['username']
return Response(content, media_type='text/plain')
app = Router([
Path('/', app=homepage),
PathPrefix('/users', app=Router([
Path('', app=users),
Path('/{username}', app=user),
]))
])
def test_router():
client = TestClient(app)
response = client.get('/')
assert response.status_code == 200
assert response.text == 'Hello, world'
response = client.get('/foo')
assert response.status_code == 404
assert response.text == 'Not found'
response = client.get('/users')
assert response.status_code == 200
assert response.text == 'All users'
response = client.get('/users/tomchristie')
assert response.status_code == 200
assert response.text == 'User tomchristie'